diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 00000000..4736653d
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,91 @@
+# AGENTS.md - JSignPdf
+
+## Project Overview
+
+JSignPdf is a Java application for adding digital signatures to PDF documents. It provides both a GUI (JavaFX default, Swing fallback via `-Djsignpdf.swing=true`) and a CLI interface.
+
+- **Java**: 11+
+- **Build**: Apache Maven multi-module
+- **Repository**: https://github.com/intoolswetrust/jsignpdf
+
+## Build Commands
+
+```bash
+mvn clean install # Build everything (with tests)
+mvn clean install -DskipTests # Build without tests
+mvn test -Dtest=BasicSigningTest # Run a single test class
+```
+
+## Module Structure
+
+```
+jsignpdf-root/
+├── jsignpdf/ # Main application (signing logic + GUI + CLI)
+├── installcert/ # Certificate installer utility
+├── distribution/ # Packaging: ZIP assembly, Windows installer, docs
+└── website/ # Docusaurus documentation site (not a Maven module)
+```
+
+## Source Code Layout
+
+All source is under `jsignpdf/src/main/java/net/sf/jsignpdf/`:
+
+```
+net.sf.jsignpdf
+├── Signer.java # Entry point - launches CLI or GUI
+├── SignerLogic.java # Core signing engine (no UI dependencies)
+├── BasicSignerOptions.java # Central model for all signing configuration
+├── SignPdfForm.java # Swing GUI (legacy, .form files are IDE-generated)
+├── fx/ # JavaFX GUI (default)
+│ ├── JSignPdfApp.java # Application entry point
+│ ├── FxLauncher.java # Static launcher called from Signer.main()
+│ ├── view/ # FXML files + controllers (MainWindow, settings panels)
+│ ├── viewmodel/ # DocumentViewModel, SigningOptionsViewModel, SignaturePlacementViewModel
+│ ├── service/ # PdfRenderService, SigningService, KeyStoreService
+│ ├── control/ # PdfPageView, SignatureOverlay
+│ └── util/ # FxResourceProvider, SwingFxImageConverter, RecentFilesManager
+├── crl/ # Certificate Revocation List handling
+├── extcsp/ # External crypto providers (CloudFoxy)
+├── preview/ # PDF page rendering (Pdf2Image)
+├── ssl/ # SSL/TLS initialization
+├── types/ # Enums and value types
+└── utils/ # KeyStoreUtils, ResourceProvider, PropertyProvider, etc.
+```
+
+## Architecture
+
+```
+CLI (SignerOptionsFromCmdLine) ──┐
+ ├──> BasicSignerOptions ──> SignerLogic.signFile()
+GUI (JavaFX / Swing) ──┘ (model) (signing engine)
+```
+
+- **`BasicSignerOptions`** is the central model. Both CLI and GUI populate it, then pass it to `SignerLogic`.
+- **`SignerLogic`** is the signing engine. It has no UI dependencies.
+- **JavaFX GUI** uses MVVM: ViewModels with JavaFX properties, FXML views with `%key` i18n, background services wrapping `SignerLogic` and `Pdf2Image`.
+
+### i18n
+
+- Resource bundles: `net/sf/jsignpdf/translations/messages*.properties`
+- CLI keys: `console.*`, `hlp.*`
+- Swing keys: `gui.*`
+- JavaFX keys: `jfx.gui.*`
+
+### Configuration
+
+- **User settings**: `~/.JSignPdf` (properties file, passwords encrypted per-user)
+- **App config**: `conf/conf.properties`
+
+## Testing
+
+- **JUnit 4** - test sources under `jsignpdf/src/test/java/`
+- **Signing tests** (`signing/` package): use `SigningTestBase` which creates temp PDFs dynamically
+- **JavaFX UI tests** (`fx/FxTranslationsTest`): headless via Monocle, loads FXML with different locales and verifies node text
+
+## CI/CD (GitHub Actions)
+
+| Workflow | Trigger | Purpose |
+|---|---|---|
+| `pr-builder.yaml` | PR/push to master | `mvn verify` with Java 11 |
+| `push-snapshots.yaml` | Push to master | Deploy SNAPSHOTs to Maven Central |
+| `do-release.yml` | Manual dispatch | Full release |
diff --git a/design-doc/jsignpdf-gui-reimplementation-plan.md b/design-doc/jsignpdf-gui-reimplementation-plan.md
new file mode 100644
index 00000000..2dc4f839
--- /dev/null
+++ b/design-doc/jsignpdf-gui-reimplementation-plan.md
@@ -0,0 +1,311 @@
+# JSignPdf JavaFX GUI Redesign - Implementation Plan
+
+## Context
+
+JSignPdf's current Swing GUI is form-centric: users fill in text fields and click "Sign It." Modern PDF tools (Adobe Acrobat, Foxit) are document-centric: users open a PDF first, then interact with it visually. This redesign replaces the Swing UI with a JavaFX PDF viewer-style application where the document is the focal point, signature placement is drag-on-preview, and settings live in a collapsible side panel. The business logic (`SignerLogic`, `BasicSignerOptions`) stays untouched.
+
+---
+
+## Main Window Layout
+
+```
++------------------------------------------------------------------+
+| Menu: File | View | Signing | Help |
++------------------------------------------------------------------+
+| Toolbar: [Open] | [ZoomIn][ZoomOut][Fit] | [<][Page X/Y][>] | [Place Sig] | [SIGN] |
++------------------------------------------------------------------+
+| Side Panel (collapsible) | PDF Preview Area |
+| +------------------------+ | +----------------------------+ |
+| | > Certificate | | | | |
+| | Keystore type: [___] | | | Rendered PDF page | |
+| | File: [____] [Browse]| | | | |
+| | Password: [____] | | | [signature rectangle] | |
+| | [Load Keys] | | | (draggable/resizable) | |
+| | Alias: [_________] | | | | |
+| +------------------------+ | +----------------------------+ |
+| | > Signature Appearance | | |
+| | > Timestamp & Validation| | |
+| | > Encryption & Rights | | |
++------------------------------------------------------------------+
+| Status: document.pdf - Page 3/12 - 1 signature [====] Ready |
++------------------------------------------------------------------+
+```
+
+## UX Improvements (prioritized)
+
+**Core (must-have for the new paradigm):**
+1. **Document-centric workflow** - open PDF first, then configure and sign
+2. **Signature placement directly on PDF preview** - click+drag rectangle, no coordinate dialogs
+3. **Drag-to-resize** signature rectangle with corner/edge handles
+4. **Page navigation** - toolbar buttons, keyboard (PgUp/PgDn), page number field
+5. **Zoom controls** - fit page, fit width, zoom in/out, percentage combo
+6. **Drag-and-drop** PDF files onto the window
+7. **Status bar** - filename, page count, existing signatures count, signing progress
+8. **Progress indication** - ProgressBar in status bar during signing
+
+**Should-have:**
+9. **Signature preview** - live rendering of what the stamp will look like
+10. **Existing signatures panel** - list signatures already on the document
+11. **Keyboard shortcuts** - Ctrl+O (open), Ctrl+S (sign), Ctrl+Z (undo placement), +/- (zoom)
+12. **Undo signature placement** before signing
+
+**Nice-to-have (future):**
+13. **Dark mode** via CSS theme switching
+14. **Recent files** in File menu
+15. **Page thumbnails** sidebar
+
+---
+
+## Architecture: MVVM
+
+```
+View (FXML + Controllers) <--> ViewModel (JavaFX Properties) <--> Model (BasicSignerOptions)
+ |
+ Service layer (javafx.concurrent.Service)
+ |
+ SignerLogic, KeyStoreUtils, Pdf2Image (unchanged)
+```
+
+### Package Structure
+
+```
+net.sf.jsignpdf.fx/
+ JSignPdfApp.java # extends Application, sets up primary Stage
+ FxLauncher.java # static launch() called from Signer.main()
+net.sf.jsignpdf.fx.view/
+ MainWindowController.java # MainWindow.fxml controller
+ CertificateSettingsController.java
+ SignatureSettingsController.java
+ TsaSettingsController.java
+ EncryptionSettingsController.java
+ OutputConsoleController.java
+net.sf.jsignpdf.fx.viewmodel/
+ DocumentViewModel.java # loaded PDF state, page, zoom
+ SigningOptionsViewModel.java # wraps BasicSignerOptions with FX properties
+ SignaturePlacementViewModel.java # rectangle position, drag state
+ AppStateViewModel.java # app-level: doc loaded?, signing in progress?, recent files
+net.sf.jsignpdf.fx.service/
+ PdfRenderService.java # wraps Pdf2Image -> JavaFX Image (background thread)
+ SigningService.java # wraps SignerLogic.signFile() (background thread)
+ KeyStoreService.java # wraps KeyStoreUtils.getKeyAliases() (background thread)
+net.sf.jsignpdf.fx.control/
+ PdfPageView.java # custom Region displaying rendered PDF page
+ SignatureOverlay.java # transparent overlay for click-drag signature rectangle
+net.sf.jsignpdf.fx.util/
+ FxResourceProvider.java # adapts ResourceProvider for JavaFX StringBindings
+ SwingFxImageConverter.java # BufferedImage <-> javafx.scene.image.Image
+ RecentFilesManager.java # persists recent file list
+```
+
+### FXML Files (in `src/main/resources/net/sf/jsignpdf/fx/view/`)
+- `MainWindow.fxml` - BorderPane with menu, toolbar, SplitPane, status bar
+- `CertificateSettings.fxml` - keystore type, file, password, alias
+- `SignatureSettings.fxml` - render mode, L2/L4 text, images, font size
+- `TsaSettings.fxml` - TSA, OCSP, CRL, proxy
+- `EncryptionSettings.fxml` - encryption type, passwords, rights
+
+### CSS (in `src/main/resources/net/sf/jsignpdf/fx/styles/`)
+- `jsignpdf.css` - light theme
+- `jsignpdf-dark.css` - dark theme (future)
+
+### Key Design Decisions
+
+**Why MVVM**: JavaFX property bindings are a natural fit. ViewModels are testable without UI.
+
+**Why keep BasicSignerOptions unchanged**: It's the contract with `SignerLogic` and CLI mode. `SigningOptionsViewModel` is a JavaFX adapter that syncs bidirectionally via `syncToOptions()` / `syncFromOptions()`.
+
+**Why `javafx-swing` dependency**: Reuses existing `Pdf2Image` (returns `BufferedImage`) via `SwingFXUtils.toFXImage()`. Avoids rewriting PDF rendering backends.
+
+**Why parallel Swing/JavaFX**: Risk mitigation. Old UI available via `-Djsignpdf.swing=true` flag until JavaFX is proven stable.
+
+---
+
+## Migration Strategy
+
+In `Signer.java`, the GUI launch becomes:
+
+```java
+if (showGui) {
+ if (Boolean.getBoolean("jsignpdf.swing")) {
+ // Legacy Swing (preserved for fallback)
+ SignPdfForm tmpForm = new SignPdfForm(...);
+ ...
+ } else {
+ // New JavaFX (default)
+ FxLauncher.launch(tmpOpts);
+ }
+}
+```
+
+Swing code is NOT deleted until the JavaFX UI ships in at least one stable release.
+
+---
+
+## Maven Changes
+
+### Dependencies (add to `jsignpdf/pom.xml`)
+
+```xml
+
+
+ org.openjfx
+ javafx-controls
+ ${openjfx.version}
+
+
+ org.openjfx
+ javafx-fxml
+ ${openjfx.version}
+
+
+ org.openjfx
+ javafx-swing
+ ${openjfx.version}
+
+
+
+
+ org.testfx
+ testfx-core
+ ${testfx.version}
+ test
+
+
+ org.testfx
+ testfx-junit
+ ${testfx.version}
+ test
+
+
+ org.testfx
+ openjfx-monocle
+ jdk-12.0.1+2
+ test
+
+```
+
+### Properties (add to root `pom.xml`)
+```xml
+17.0.2
+4.0.18
+```
+
+### Plugin (add to `jsignpdf/pom.xml`)
+```xml
+
+ org.openjfx
+ javafx-maven-plugin
+ 0.0.8
+
+ net.sf.jsignpdf.Signer
+
+
+```
+
+### Surefire argLine for headless TestFX
+```xml
+-Dtestfx.robot=glass -Dglass.platform=Monocle -Dmonocle.platform=Headless
+```
+
+---
+
+## Testing Strategy
+
+### Unit Tests (plain JUnit, no FX runtime needed)
+- `SigningOptionsViewModelTest` - verify `syncToOptions()` / `syncFromOptions()` round-trips all fields correctly
+- `SignaturePlacementViewModelTest` - verify coordinate calculations, bounds clamping
+- `DocumentViewModelTest` - verify page navigation logic, zoom level calculations
+
+### UI Integration Tests (TestFX)
+- `MainWindowTest` - app starts, menu bar renders, toolbar present, status bar shows
+- `DocumentLoadTest` - open test PDF, page count in status bar, page navigation works
+- `SignaturePlacementTest` - click+drag on preview, verify rectangle coordinates on ViewModel
+- `SigningWorkflowTest` - full end-to-end: open PDF, load test keystore, place sig, click Sign, verify output file has valid signature (reuses existing `PdfSignatureValidator`)
+
+### CI Configuration
+- TestFX runs headlessly via Monocle (no display server needed)
+- Existing `signing/` JUnit tests remain unchanged and keep running
+
+---
+
+## Phased Implementation Order
+
+### Phase 1: Foundation
+- Add OpenJFX + TestFX dependencies to pom.xml
+- Create `JSignPdfApp`, `FxLauncher`, parallel launch in `Signer.java`
+- Create `MainWindow.fxml` with BorderPane skeleton: menu bar, toolbar (placeholder buttons), center StackPane with "Drop PDF here" label, status bar
+- Create `MainWindowController` with stub handlers
+- Create `jsignpdf.css` base stylesheet
+- **Verify**: JavaFX app starts and shows the empty window
+
+### Phase 2: PDF Viewing
+- Create `PdfPageView` custom control
+- Create `DocumentViewModel` (file, page count, current page, zoom level)
+- Create `PdfRenderService` wrapping `Pdf2Image` + `SwingFXUtils`
+- Implement File > Open (FileChooser) and drag-and-drop
+- Implement page navigation (toolbar, PgUp/PgDn)
+- Implement zoom (fit page, fit width, +/-)
+- Show document info in status bar
+- **Verify**: Can open a PDF, navigate pages, zoom
+
+### Phase 3: Certificate Configuration
+- Create `SigningOptionsViewModel` wrapping `BasicSignerOptions`
+- Create `CertificateSettings.fxml` + controller
+- Bind keystore type, file, password, alias to ViewModel
+- Implement "Load Keys" via `KeyStoreService`
+- Wire into MainWindow via `` in the side panel Accordion
+- **Verify**: Can select keystore, load keys, pick alias
+
+### Phase 4: Signature Placement
+- Create `SignatureOverlay` with mouse drag handling + resize handles
+- Create `SignaturePlacementViewModel`
+- Implement "Place Signature" toggle in toolbar
+- Show semi-transparent rectangle on PDF with drag/resize
+- Coordinate display in side panel
+- Undo placement (Ctrl+Z)
+- **Verify**: Can place, move, resize, undo signature rectangle
+
+### Phase 5: Signing Workflow
+- Create `SigningService` wrapping `SignerLogic`
+- Wire "Sign" button: sync ViewModel -> options -> SigningService
+- ProgressBar in status bar
+- Success/failure notification
+- Output console pane for log viewing
+- **Verify**: Full sign workflow works, output PDF has valid signature
+
+### Phase 6: Advanced Settings
+- Create `SignatureSettings.fxml` - render mode, L2/L4 text, images, font size, Acro6 layers
+- Create `TsaSettings.fxml` - TSA, OCSP, CRL, proxy
+- Create `EncryptionSettings.fxml` - encryption, passwords, rights
+- Collapsed by default, "Show Advanced" toggle expands them
+- **Verify**: All settings from original UI are accessible
+
+### Phase 7: Polish & Testing
+- Write TestFX tests (MainWindowTest, DocumentLoadTest, SignaturePlacementTest, SigningWorkflowTest)
+- Write ViewModel unit tests
+- Signature preview (live render of stamp appearance)
+- Existing signatures panel
+- Keyboard shortcuts
+- Final i18n pass - add keys for new UI elements
+- **Verify**: All tests pass, headless CI works
+
+### Phase 8: Cleanup (future release)
+- Remove Swing classes (SignPdfForm, VisibleSignatureDialog, TsaDialog, etc.)
+- Remove `-Djsignpdf.swing` fallback flag
+- Update distribution scripts
+
+---
+
+## Critical Files
+
+| File | Role | Change |
+|------|------|--------|
+| `jsignpdf/pom.xml` | Module build | Add OpenJFX, TestFX deps + plugins |
+| `pom.xml` (root) | Parent build | Add version properties |
+| `Signer.java` | Entry point | Add JavaFX launch path |
+| `BasicSignerOptions.java` | Model | **No change** |
+| `SignerLogic.java` | Signing logic | **No change** |
+| `preview/Pdf2Image.java` | PDF rendering | **No change** (reused by PdfRenderService) |
+| `preview/SelectionImage.java` | Rectangle selection | **No change** (reference for SignatureOverlay) |
+| `utils/ResourceProvider.java` | i18n | **No change** (wrapped by FxResourceProvider) |
+| All files under `net.sf.jsignpdf.fx/` | New JavaFX GUI | **All new** |
diff --git a/distribution/doc/ChangeLog.txt b/distribution/doc/ChangeLog.txt
index bcd9b714..6267dd41 100644
--- a/distribution/doc/ChangeLog.txt
+++ b/distribution/doc/ChangeLog.txt
@@ -1,3 +1,8 @@
+2026-03-30: New JavaFX GUI with PDF preview, signature placement, and full signing workflow
+2026-03-30: Add i18n support (19 languages) for the new JavaFX GUI
+2026-03-30: Add headless JavaFX UI translation tests
+2026-03-30: Fix NPE in KeyStoreUtils.getPkInfo when key alias is null
+2026-03-30: Fix NPE in SignerLogic.signFile when getPkInfo returns null
2026-02-21: Add integration tests for the PDF signing pipeline (#292)
2026-02-21: Bump org.apache.maven.plugins:maven-assembly-plugin from 3.7.1 to 3.8.0 (#284)
2026-02-21: Bump org.apache.maven.plugins:maven-shade-plugin from 3.5.0 to 3.6.1 (#283)
diff --git a/distribution/windows/JSignPdf-swing.l4j.ini b/distribution/windows/JSignPdf-swing.l4j.ini
new file mode 100644
index 00000000..053c935d
--- /dev/null
+++ b/distribution/windows/JSignPdf-swing.l4j.ini
@@ -0,0 +1,10 @@
+# Launch4j runtime config
+-Xms1g
+-Xmx1g
+--add-exports jdk.crypto.cryptoki/sun.security.pkcs11=ALL-UNNAMED
+--add-exports jdk.crypto.cryptoki/sun.security.pkcs11.wrapper=ALL-UNNAMED
+--add-exports java.base/sun.security.action=ALL-UNNAMED
+--add-exports java.base/sun.security.rsa=ALL-UNNAMED
+--add-opens java.base/sun.security.util=ALL-UNNAMED
+-Djsignpdf.home="%EXEDIR%"
+-Djsignpdf.swing=true
diff --git a/distribution/windows/JSignPdf.iss b/distribution/windows/JSignPdf.iss
index 5bf0b6ee..fe7c92ab 100644
--- a/distribution/windows/JSignPdf.iss
+++ b/distribution/windows/JSignPdf.iss
@@ -20,7 +20,7 @@ VersionInfoVersion={#MyAppVersionWin}
VersionInfoCompany=Josef Cacek
VersionInfoDescription=JSignPdf adds digital signatures to PDF documents
AppPublisher=Josef Cacek
-AppSupportURL=http://jsignpdf.sourceforge.net/
+AppSupportURL=http://intoolswetrust.github.io/jsignpdf/
AppVersion={#MyAppVersion}
OutputDir={#OutputDir}
;WizardStyle=modern
@@ -31,6 +31,7 @@ UninstallDisplayIcon={app}\JSignPdf.exe
[Icons]
Name: {group}\JSignPdf {#MyAppVersion}; Filename: {app}\JSignPdf.exe; Components: ; WorkingDir: {app}
+Name: {group}\JSignPdf {#MyAppVersion} (Swing); Filename: {app}\JSignPdf-swing.exe; Components: ; WorkingDir: {app}
Name: {group}\InstallCert Tool; Filename: {app}\InstallCert.exe; Components: ; WorkingDir: {app}
Name: {group}\JSignPdf Guide; Filename: {app}\docs\JSignPdf.pdf; Components:
Name: {group}\Uninstall {#MyAppName}; Filename: {uninstallexe}; Components:
diff --git a/distribution/windows/ant-build-create-launchers.xml b/distribution/windows/ant-build-create-launchers.xml
index 72765fcc..f89f43eb 100644
--- a/distribution/windows/ant-build-create-launchers.xml
+++ b/distribution/windows/ant-build-create-launchers.xml
@@ -33,6 +33,24 @@
+
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ ${argLine}
+ -Dglass.platform=Monocle -Dmonocle.platform=Headless
+ -Dprism.order=sw
+
+
+
org.apache.maven.plugins
maven-dependency-plugin
@@ -84,6 +95,23 @@
+
+
+ org.openjfx
+ javafx-controls
+ ${openjfx.version}
+
+
+ org.openjfx
+ javafx-fxml
+ ${openjfx.version}
+
+
+ org.openjfx
+ javafx-swing
+ ${openjfx.version}
+
+
com.github.librepdf
openpdf
@@ -124,5 +152,11 @@
com.github.kwart.jsign
jsign-pkcs11
+
+ org.testfx
+ openjfx-monocle
+ 11.0.2
+ test
+
diff --git a/jsignpdf/src/main/java/net/sf/jsignpdf/BasicSignerOptions.java b/jsignpdf/src/main/java/net/sf/jsignpdf/BasicSignerOptions.java
index 6c26b993..04bea84c 100644
--- a/jsignpdf/src/main/java/net/sf/jsignpdf/BasicSignerOptions.java
+++ b/jsignpdf/src/main/java/net/sf/jsignpdf/BasicSignerOptions.java
@@ -31,7 +31,9 @@
import java.net.InetSocketAddress;
import java.net.Proxy;
+import java.util.Arrays;
import java.util.Locale;
+import java.util.Objects;
import net.sf.jsignpdf.types.CertificationLevel;
import net.sf.jsignpdf.types.HashAlgorithm;
@@ -47,14 +49,9 @@
/**
* Options for PDF signer.
- *
- * @author Josef Cacek
*/
public class BasicSignerOptions {
- // private final static Logger LOGGER =
- // Logger.getLogger(BasicSignerOptions.class);
-
protected final PropertyProvider props = PropertyProvider.getInstance();
protected final JSignEncryptor encryptor = new JSignEncryptor();
@@ -289,10 +286,10 @@ public void storeOptions() {
props.setProperty(Constants.PROPERTY_STOREPWD, isStorePasswords());
setEncrypted(Constants.EPROPERTY_USERHOME, Constants.USER_HOME);
if (isStorePasswords()) {
- setEncrypted(Constants.EPROPERTY_KS_PWD, new String(getKsPasswd()));
- setEncrypted(Constants.EPROPERTY_KEY_PWD, new String(getKeyPasswd()));
- setEncrypted(Constants.EPROPERTY_OWNER_PWD, new String(getPdfOwnerPwd()));
- setEncrypted(Constants.EPROPERTY_USER_PWD, new String(getPdfUserPwd()));
+ setEncrypted(Constants.EPROPERTY_KS_PWD, getKsPasswdStr());
+ setEncrypted(Constants.EPROPERTY_KEY_PWD, getKeyPasswdStr());
+ setEncrypted(Constants.EPROPERTY_OWNER_PWD, getPdfOwnerPwdStr());
+ setEncrypted(Constants.EPROPERTY_USER_PWD, getPdfUserPwdStr());
setEncrypted(Constants.EPROPERTY_TSA_PWD, getTsaPasswd());
setEncrypted(Constants.EPROPERTY_TSA_CERT_PWD, getTsaCertFilePwd());
} else {
@@ -1198,4 +1195,138 @@ protected void setCmdLine(String[] cmdLine) {
this.cmdLine = cmdLine;
}
+ /**
+ * Creates a shallow copy of this options instance. Enum and String fields are
+ * effectively immutable, so shallow copy is sufficient for thread-safety.
+ * char[] fields are defensively copied.
+ *
+ * @return a new BasicSignerOptions with the same field values
+ */
+ public BasicSignerOptions createCopy() {
+ BasicSignerOptions copy = new BasicSignerOptions();
+ copy.setKsType(getKsType());
+ copy.setKsFile(getKsFile());
+ copy.setKsPasswd(getKsPasswd() != null ? getKsPasswd().clone() : null);
+ copy.setKeyAlias(getKeyAlias());
+ copy.setKeyIndex(getKeyIndex());
+ copy.setKeyPasswd(getKeyPasswd() != null ? getKeyPasswd().clone() : null);
+ copy.setInFile(getInFile());
+ copy.setOutFile(getOutFile());
+ copy.setSignerName(getSignerName());
+ copy.setReason(getReason());
+ copy.setLocation(getLocation());
+ copy.setContact(getContact());
+ copy.setListener(getListener());
+ copy.setAppend(isAppend());
+ copy.setAdvanced(isAdvanced());
+ copy.setPdfEncryption(getPdfEncryption());
+ copy.setPdfOwnerPwd(getPdfOwnerPwd() != null ? getPdfOwnerPwd().clone() : null);
+ copy.setPdfUserPwd(getPdfUserPwd() != null ? getPdfUserPwd().clone() : null);
+ copy.setPdfEncryptionCertFile(getPdfEncryptionCertFile());
+ copy.setCertLevel(getCertLevel());
+ copy.setHashAlgorithm(getHashAlgorithm());
+ copy.setStorePasswords(isStorePasswords());
+ copy.setRightPrinting(getRightPrinting());
+ copy.setRightCopy(isRightCopy());
+ copy.setRightAssembly(isRightAssembly());
+ copy.setRightFillIn(isRightFillIn());
+ copy.setRightScreanReaders(isRightScreanReaders());
+ copy.setRightModifyAnnotations(isRightModifyAnnotations());
+ copy.setRightModifyContents(isRightModifyContents());
+ copy.setVisible(isVisible());
+ copy.setPage(getPage());
+ copy.setPositionLLX(getPositionLLX());
+ copy.setPositionLLY(getPositionLLY());
+ copy.setPositionURX(getPositionURX());
+ copy.setPositionURY(getPositionURY());
+ copy.setBgImgScale(getBgImgScale());
+ copy.setRenderMode(getRenderMode());
+ copy.setL2Text(getL2Text());
+ copy.setL4Text(getL4Text());
+ copy.setL2TextFontSize(getL2TextFontSize());
+ copy.setImgPath(getImgPath());
+ copy.setBgImgPath(getBgImgPath());
+ copy.setAcro6Layers(isAcro6Layers());
+ copy.setTimestamp(isTimestamp());
+ copy.setTsaUrl(getTsaUrl());
+ copy.setTsaServerAuthn(getTsaServerAuthn());
+ copy.setTsaUser(getTsaUser());
+ copy.setTsaPasswd(getTsaPasswd());
+ copy.setTsaCertFileType(getTsaCertFileType());
+ copy.setTsaCertFile(getTsaCertFile());
+ copy.setTsaCertFilePwd(getTsaCertFilePwd());
+ copy.setTsaPolicy(getTsaPolicy());
+ copy.setTsaHashAlg(getTsaHashAlg());
+ copy.setOcspEnabled(isOcspEnabled());
+ copy.setOcspServerUrl(getOcspServerUrl());
+ copy.setCrlEnabled(isCrlEnabled());
+ copy.setProxyType(getProxyType());
+ copy.setProxyHost(getProxyHost());
+ copy.setProxyPort(getProxyPort());
+ return copy;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + Arrays.hashCode(cmdLine);
+ result = prime * result + Arrays.hashCode(keyPasswd);
+ result = prime * result + Arrays.hashCode(ksPasswd);
+ result = prime * result + Arrays.hashCode(pdfOwnerPwd);
+ result = prime * result + Arrays.hashCode(pdfUserPwd);
+ result = prime * result + Objects.hash(acro6Layers, advanced, append, bgImgPath, bgImgScale, certLevel, contact,
+ crlEnabled, encryptor, hashAlgorithm, imgPath, inFile, keyAlias, keyIndex, ksFile, ksType, l2Text,
+ l2TextFontSize, l4Text, listener, location, ocspEnabled, ocspServerUrl, outFile, page, pdfEncryption,
+ pdfEncryptionCertFile, positionLLX, positionLLY, positionURX, positionURY, propertiesFilePath, props, proxyHost,
+ proxyPort, proxyType, reason, renderMode, rightAssembly, rightCopy, rightFillIn, rightModifyAnnotations,
+ rightModifyContents, rightPrinting, rightScreanReaders, signerName, storePasswords, timestamp, tsaCertFile,
+ tsaCertFilePwd, tsaCertFileType, tsaHashAlg, tsaPasswd, tsaPolicy, tsaServerAuthn, tsaUrl, tsaUser, visible);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ BasicSignerOptions other = (BasicSignerOptions) obj;
+ return acro6Layers == other.acro6Layers && advanced == other.advanced && append == other.append
+ && Objects.equals(bgImgPath, other.bgImgPath)
+ && Float.floatToIntBits(bgImgScale) == Float.floatToIntBits(other.bgImgScale) && certLevel == other.certLevel
+ && Arrays.equals(cmdLine, other.cmdLine) && Objects.equals(contact, other.contact)
+ && crlEnabled == other.crlEnabled && Objects.equals(encryptor, other.encryptor)
+ && hashAlgorithm == other.hashAlgorithm && Objects.equals(imgPath, other.imgPath)
+ && Objects.equals(inFile, other.inFile) && Objects.equals(keyAlias, other.keyAlias)
+ && keyIndex == other.keyIndex && Arrays.equals(keyPasswd, other.keyPasswd)
+ && Objects.equals(ksFile, other.ksFile) && Arrays.equals(ksPasswd, other.ksPasswd)
+ && Objects.equals(ksType, other.ksType) && Objects.equals(l2Text, other.l2Text)
+ && Float.floatToIntBits(l2TextFontSize) == Float.floatToIntBits(other.l2TextFontSize)
+ && Objects.equals(l4Text, other.l4Text) && Objects.equals(listener, other.listener)
+ && Objects.equals(location, other.location) && ocspEnabled == other.ocspEnabled
+ && Objects.equals(ocspServerUrl, other.ocspServerUrl) && Objects.equals(outFile, other.outFile)
+ && page == other.page && pdfEncryption == other.pdfEncryption
+ && Objects.equals(pdfEncryptionCertFile, other.pdfEncryptionCertFile)
+ && Arrays.equals(pdfOwnerPwd, other.pdfOwnerPwd) && Arrays.equals(pdfUserPwd, other.pdfUserPwd)
+ && Float.floatToIntBits(positionLLX) == Float.floatToIntBits(other.positionLLX)
+ && Float.floatToIntBits(positionLLY) == Float.floatToIntBits(other.positionLLY)
+ && Float.floatToIntBits(positionURX) == Float.floatToIntBits(other.positionURX)
+ && Float.floatToIntBits(positionURY) == Float.floatToIntBits(other.positionURY)
+ && Objects.equals(propertiesFilePath, other.propertiesFilePath) && Objects.equals(props, other.props)
+ && Objects.equals(proxyHost, other.proxyHost) && proxyPort == other.proxyPort && proxyType == other.proxyType
+ && Objects.equals(reason, other.reason) && renderMode == other.renderMode
+ && rightAssembly == other.rightAssembly && rightCopy == other.rightCopy && rightFillIn == other.rightFillIn
+ && rightModifyAnnotations == other.rightModifyAnnotations && rightModifyContents == other.rightModifyContents
+ && rightPrinting == other.rightPrinting && rightScreanReaders == other.rightScreanReaders
+ && Objects.equals(signerName, other.signerName) && storePasswords == other.storePasswords
+ && timestamp == other.timestamp && Objects.equals(tsaCertFile, other.tsaCertFile)
+ && Objects.equals(tsaCertFilePwd, other.tsaCertFilePwd)
+ && Objects.equals(tsaCertFileType, other.tsaCertFileType) && Objects.equals(tsaHashAlg, other.tsaHashAlg)
+ && Objects.equals(tsaPasswd, other.tsaPasswd) && Objects.equals(tsaPolicy, other.tsaPolicy)
+ && tsaServerAuthn == other.tsaServerAuthn && Objects.equals(tsaUrl, other.tsaUrl)
+ && Objects.equals(tsaUser, other.tsaUser) && visible == other.visible;
+ }
}
diff --git a/jsignpdf/src/main/java/net/sf/jsignpdf/Constants.java b/jsignpdf/src/main/java/net/sf/jsignpdf/Constants.java
index f83b7f0e..74dfaadd 100644
--- a/jsignpdf/src/main/java/net/sf/jsignpdf/Constants.java
+++ b/jsignpdf/src/main/java/net/sf/jsignpdf/Constants.java
@@ -208,6 +208,8 @@ public class Constants {
public static final String PROPERTY_PROXY_HOST = "proxy.host";
public static final String PROPERTY_PROXY_PORT = "proxy.port";
+ public static final String PROPERTY_RECENT_FILE_PREFIX = "recentFile.";
+
/**
* Property name.
*/
diff --git a/jsignpdf/src/main/java/net/sf/jsignpdf/Signer.java b/jsignpdf/src/main/java/net/sf/jsignpdf/Signer.java
index c1b5a9ee..1fbefec7 100644
--- a/jsignpdf/src/main/java/net/sf/jsignpdf/Signer.java
+++ b/jsignpdf/src/main/java/net/sf/jsignpdf/Signer.java
@@ -49,6 +49,7 @@
import javax.swing.UIManager;
import javax.swing.WindowConstants;
+import net.sf.jsignpdf.fx.FxLauncher;
import net.sf.jsignpdf.ssl.SSLInitializer;
import net.sf.jsignpdf.utils.ConfigProvider;
import net.sf.jsignpdf.utils.GuiUtils;
@@ -151,15 +152,21 @@ public static void main(String[] args) {
}
if (showGui) {
- try {
- UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
- } catch (Exception e) {
- System.err.println("Can't set Look&Feel.");
+ if (Boolean.getBoolean("jsignpdf.swing")) {
+ // Legacy Swing GUI (preserved for fallback)
+ try {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ } catch (Exception e) {
+ System.err.println("Can't set Look&Feel.");
+ }
+ SignPdfForm tmpForm = new SignPdfForm(WindowConstants.EXIT_ON_CLOSE, tmpOpts);
+ tmpForm.pack();
+ GuiUtils.center(tmpForm);
+ tmpForm.setVisible(true);
+ } else {
+ // New JavaFX GUI (default)
+ FxLauncher.launch(tmpOpts);
}
- SignPdfForm tmpForm = new SignPdfForm(WindowConstants.EXIT_ON_CLOSE, tmpOpts);
- tmpForm.pack();
- GuiUtils.center(tmpForm);
- tmpForm.setVisible(true);
}
}
diff --git a/jsignpdf/src/main/java/net/sf/jsignpdf/SignerLogic.java b/jsignpdf/src/main/java/net/sf/jsignpdf/SignerLogic.java
index 56a4f9fa..7c08e2ee 100644
--- a/jsignpdf/src/main/java/net/sf/jsignpdf/SignerLogic.java
+++ b/jsignpdf/src/main/java/net/sf/jsignpdf/SignerLogic.java
@@ -152,6 +152,10 @@ public boolean signFile() {
}
} else {
pkInfo = KeyStoreUtils.getPkInfo(options);
+ if (pkInfo == null) {
+ LOGGER.info(RES.get("console.certificateChainEmpty"));
+ return false;
+ }
key = pkInfo.getKey();
chain = pkInfo.getChain();
}
diff --git a/jsignpdf/src/main/java/net/sf/jsignpdf/fx/FxLauncher.java b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/FxLauncher.java
new file mode 100644
index 00000000..b5b5d682
--- /dev/null
+++ b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/FxLauncher.java
@@ -0,0 +1,22 @@
+package net.sf.jsignpdf.fx;
+
+import net.sf.jsignpdf.BasicSignerOptions;
+
+/**
+ * Static launcher for the JavaFX GUI, called from {@link net.sf.jsignpdf.Signer#main}.
+ */
+public final class FxLauncher {
+
+ private FxLauncher() {
+ }
+
+ /**
+ * Launches the JavaFX application with the given initial options.
+ *
+ * @param opts initial signer options (may be null)
+ */
+ public static void launch(BasicSignerOptions opts) {
+ JSignPdfApp.setInitialOptions(opts);
+ javafx.application.Application.launch(JSignPdfApp.class);
+ }
+}
diff --git a/jsignpdf/src/main/java/net/sf/jsignpdf/fx/JSignPdfApp.java b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/JSignPdfApp.java
new file mode 100644
index 00000000..fbd04873
--- /dev/null
+++ b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/JSignPdfApp.java
@@ -0,0 +1,55 @@
+package net.sf.jsignpdf.fx;
+
+import java.util.ResourceBundle;
+
+import javafx.application.Application;
+import javafx.fxml.FXMLLoader;
+import javafx.scene.Parent;
+import javafx.scene.Scene;
+import javafx.scene.image.Image;
+import javafx.stage.Stage;
+import net.sf.jsignpdf.BasicSignerOptions;
+import net.sf.jsignpdf.Constants;
+import net.sf.jsignpdf.fx.view.MainWindowController;
+
+/**
+ * JavaFX Application entry point for JSignPdf.
+ */
+public class JSignPdfApp extends Application {
+
+ private static BasicSignerOptions initialOptions;
+
+ static void setInitialOptions(BasicSignerOptions opts) {
+ initialOptions = opts;
+ }
+
+ @Override
+ public void start(Stage primaryStage) throws Exception {
+ ResourceBundle bundle = ResourceBundle.getBundle(Constants.RESOURCE_BUNDLE_BASE);
+ FXMLLoader loader = new FXMLLoader(
+ getClass().getResource("/net/sf/jsignpdf/fx/view/MainWindow.fxml"), bundle);
+ Parent root = loader.load();
+
+ MainWindowController controller = loader.getController();
+ controller.setStage(primaryStage);
+
+ // Create options and load persisted configuration
+ BasicSignerOptions opts = initialOptions != null ? initialOptions : new BasicSignerOptions();
+ opts.loadOptions();
+ controller.initFromOptions(opts);
+
+ Scene scene = new Scene(root, 1100, 750);
+ scene.getStylesheets().add(
+ getClass().getResource("/net/sf/jsignpdf/fx/styles/jsignpdf.css").toExternalForm());
+
+ primaryStage.setTitle("JSignPdf " + Constants.VERSION);
+ primaryStage.getIcons().add(
+ new Image(getClass().getResourceAsStream("/net/sf/jsignpdf/signedpdf32.png")));
+ primaryStage.setScene(scene);
+
+ // Store configuration on window close
+ primaryStage.setOnCloseRequest(event -> controller.storeAndCleanup());
+
+ primaryStage.show();
+ }
+}
diff --git a/jsignpdf/src/main/java/net/sf/jsignpdf/fx/control/PdfPageView.java b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/control/PdfPageView.java
new file mode 100644
index 00000000..71911a3d
--- /dev/null
+++ b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/control/PdfPageView.java
@@ -0,0 +1,63 @@
+package net.sf.jsignpdf.fx.control;
+
+import javafx.beans.property.DoubleProperty;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleDoubleProperty;
+import javafx.beans.property.SimpleObjectProperty;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+import javafx.scene.layout.Region;
+
+/**
+ * Custom Region that displays a rendered PDF page with zoom support.
+ * The image is scaled by the zoomLevel property.
+ */
+public class PdfPageView extends Region {
+
+ private final ImageView imageView = new ImageView();
+ private final ObjectProperty pageImage = new SimpleObjectProperty<>();
+ private final DoubleProperty zoomLevel = new SimpleDoubleProperty(1.0);
+
+ public PdfPageView() {
+ getChildren().add(imageView);
+ imageView.setPreserveRatio(true);
+ imageView.setSmooth(true);
+
+ // Bind image
+ imageView.imageProperty().bind(pageImage);
+
+ // Update size when image or zoom changes
+ pageImage.addListener((obs, o, n) -> updateSize());
+ zoomLevel.addListener((obs, o, n) -> updateSize());
+
+ getStyleClass().add("pdf-page-view");
+ }
+
+ private void updateSize() {
+ Image img = pageImage.get();
+ if (img != null) {
+ double zoom = zoomLevel.get();
+ double w = img.getWidth() * zoom;
+ double h = img.getHeight() * zoom;
+ imageView.setFitWidth(w);
+ imageView.setFitHeight(h);
+ setPrefSize(w, h);
+ setMinSize(w, h);
+ setMaxSize(w, h);
+ }
+ }
+
+ @Override
+ protected void layoutChildren() {
+ imageView.relocate(0, 0);
+ }
+
+ // --- Properties ---
+ public ObjectProperty pageImageProperty() { return pageImage; }
+ public Image getPageImage() { return pageImage.get(); }
+ public void setPageImage(Image image) { pageImage.set(image); }
+
+ public DoubleProperty zoomLevelProperty() { return zoomLevel; }
+ public double getZoomLevel() { return zoomLevel.get(); }
+ public void setZoomLevel(double zoom) { zoomLevel.set(zoom); }
+}
diff --git a/jsignpdf/src/main/java/net/sf/jsignpdf/fx/control/SignatureOverlay.java b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/control/SignatureOverlay.java
new file mode 100644
index 00000000..e43bf33a
--- /dev/null
+++ b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/control/SignatureOverlay.java
@@ -0,0 +1,268 @@
+package net.sf.jsignpdf.fx.control;
+
+import javafx.beans.binding.Bindings;
+import javafx.scene.Cursor;
+import javafx.scene.input.MouseEvent;
+import javafx.scene.layout.Pane;
+import javafx.scene.paint.Color;
+import javafx.scene.shape.Rectangle;
+import net.sf.jsignpdf.fx.viewmodel.SignaturePlacementViewModel;
+
+/**
+ * Transparent overlay pane for click-drag signature rectangle placement
+ * on top of the PDF page view.
+ */
+public class SignatureOverlay extends Pane {
+
+ private static final double HANDLE_SIZE = 8;
+
+ private final SignaturePlacementViewModel viewModel;
+ private final Rectangle sigRect = new Rectangle();
+ private final Rectangle[] handles = new Rectangle[4]; // corners: TL, TR, BL, BR
+
+ // Drag state
+ private double dragStartX, dragStartY;
+ private double dragStartRelX, dragStartRelY, dragStartRelW, dragStartRelH;
+ private DragMode dragMode = DragMode.NONE;
+
+ private enum DragMode { NONE, CREATE, MOVE, RESIZE_TL, RESIZE_TR, RESIZE_BL, RESIZE_BR }
+
+ public SignatureOverlay(SignaturePlacementViewModel viewModel) {
+ this.viewModel = viewModel;
+ setPickOnBounds(true);
+
+ // Setup signature rectangle
+ sigRect.getStyleClass().add("signature-rect");
+ sigRect.setVisible(false);
+ getChildren().add(sigRect);
+
+ // Setup corner handles
+ for (int i = 0; i < 4; i++) {
+ handles[i] = new Rectangle(HANDLE_SIZE, HANDLE_SIZE);
+ handles[i].getStyleClass().add("signature-handle");
+ handles[i].setVisible(false);
+ getChildren().add(handles[i]);
+ }
+
+ // Mouse handlers
+ setOnMousePressed(this::onMousePressed);
+ setOnMouseDragged(this::onMouseDragged);
+ setOnMouseReleased(this::onMouseReleased);
+ setOnMouseMoved(this::onMouseMoved);
+
+ // Bind visibility to placed state
+ viewModel.placedProperty().addListener((obs, o, n) -> {
+ sigRect.setVisible(n);
+ for (Rectangle h : handles) h.setVisible(n);
+ if (!n) setCursor(Cursor.DEFAULT);
+ });
+
+ // Bind rectangle position/size to ViewModel
+ viewModel.relXProperty().addListener((obs, o, n) -> updateRectPosition());
+ viewModel.relYProperty().addListener((obs, o, n) -> updateRectPosition());
+ viewModel.relWidthProperty().addListener((obs, o, n) -> updateRectPosition());
+ viewModel.relHeightProperty().addListener((obs, o, n) -> updateRectPosition());
+
+ // Update when overlay size changes
+ widthProperty().addListener((obs, o, n) -> updateRectPosition());
+ heightProperty().addListener((obs, o, n) -> updateRectPosition());
+ }
+
+ private void updateRectPosition() {
+ double w = getWidth();
+ double h = getHeight();
+ if (w <= 0 || h <= 0) return;
+
+ double rx = viewModel.getRelX() * w;
+ double ry = viewModel.getRelY() * h;
+ double rw = viewModel.getRelWidth() * w;
+ double rh = viewModel.getRelHeight() * h;
+
+ sigRect.setX(rx);
+ sigRect.setY(ry);
+ sigRect.setWidth(rw);
+ sigRect.setHeight(rh);
+
+ // TL
+ handles[0].setX(rx - HANDLE_SIZE / 2);
+ handles[0].setY(ry - HANDLE_SIZE / 2);
+ // TR
+ handles[1].setX(rx + rw - HANDLE_SIZE / 2);
+ handles[1].setY(ry - HANDLE_SIZE / 2);
+ // BL
+ handles[2].setX(rx - HANDLE_SIZE / 2);
+ handles[2].setY(ry + rh - HANDLE_SIZE / 2);
+ // BR
+ handles[3].setX(rx + rw - HANDLE_SIZE / 2);
+ handles[3].setY(ry + rh - HANDLE_SIZE / 2);
+ }
+
+ private void onMousePressed(MouseEvent e) {
+ double mx = e.getX();
+ double my = e.getY();
+ double w = getWidth();
+ double h = getHeight();
+
+ dragStartX = mx;
+ dragStartY = my;
+ dragStartRelX = viewModel.getRelX();
+ dragStartRelY = viewModel.getRelY();
+ dragStartRelW = viewModel.getRelWidth();
+ dragStartRelH = viewModel.getRelHeight();
+
+ if (viewModel.isPlaced()) {
+ // Check if clicking on a handle
+ DragMode handleMode = getHandleAt(mx, my);
+ if (handleMode != DragMode.NONE) {
+ dragMode = handleMode;
+ e.consume();
+ return;
+ }
+ // Check if clicking inside the rectangle (move)
+ double rx = viewModel.getRelX() * w;
+ double ry = viewModel.getRelY() * h;
+ double rw = viewModel.getRelWidth() * w;
+ double rh = viewModel.getRelHeight() * h;
+ if (mx >= rx && mx <= rx + rw && my >= ry && my <= ry + rh) {
+ dragMode = DragMode.MOVE;
+ e.consume();
+ return;
+ }
+ }
+
+ // Require Shift to replace an existing rectangle
+ if (viewModel.isPlaced() && !e.isShiftDown()) {
+ dragMode = DragMode.NONE;
+ e.consume();
+ return;
+ }
+
+ // Start creating a new rectangle
+ dragMode = DragMode.CREATE;
+ viewModel.setRelX(mx / w);
+ viewModel.setRelY(my / h);
+ viewModel.setRelWidth(0.02);
+ viewModel.setRelHeight(0.02);
+ // Update drag start values to match the new rectangle
+ dragStartRelW = 0.02;
+ dragStartRelH = 0.02;
+ viewModel.setPlaced(true);
+ e.consume();
+ }
+
+ private void onMouseDragged(MouseEvent e) {
+ if (dragMode == DragMode.NONE) return;
+
+ double mx = e.getX();
+ double my = e.getY();
+ double w = getWidth();
+ double h = getHeight();
+ double dx = (mx - dragStartX) / w;
+ double dy = (my - dragStartY) / h;
+
+ switch (dragMode) {
+ case CREATE:
+ // Normalize origin and extent so dragging in any direction works
+ double endRelX = mx / w;
+ double endRelY = my / h;
+ double originX = Math.min(dragStartX / w, endRelX);
+ double originY = Math.min(dragStartY / h, endRelY);
+ double extentW = Math.abs(endRelX - dragStartX / w);
+ double extentH = Math.abs(endRelY - dragStartY / h);
+ viewModel.setRelX(originX);
+ viewModel.setRelY(originY);
+ viewModel.setRelWidth(Math.max(0.02, extentW));
+ viewModel.setRelHeight(Math.max(0.02, extentH));
+ break;
+ case RESIZE_BR:
+ viewModel.setRelWidth(Math.max(0.02, dragStartRelW + dx));
+ viewModel.setRelHeight(Math.max(0.02, dragStartRelH + dy));
+ break;
+ case MOVE:
+ viewModel.setRelX(clamp(dragStartRelX + dx, 0, 1 - viewModel.getRelWidth()));
+ viewModel.setRelY(clamp(dragStartRelY + dy, 0, 1 - viewModel.getRelHeight()));
+ break;
+ case RESIZE_TL:
+ viewModel.setRelX(clamp(dragStartRelX + dx, 0, dragStartRelX + dragStartRelW - 0.02));
+ viewModel.setRelY(clamp(dragStartRelY + dy, 0, dragStartRelY + dragStartRelH - 0.02));
+ viewModel.setRelWidth(dragStartRelW - (viewModel.getRelX() - dragStartRelX));
+ viewModel.setRelHeight(dragStartRelH - (viewModel.getRelY() - dragStartRelY));
+ break;
+ case RESIZE_TR:
+ viewModel.setRelWidth(Math.max(0.02, dragStartRelW + dx));
+ viewModel.setRelY(clamp(dragStartRelY + dy, 0, dragStartRelY + dragStartRelH - 0.02));
+ viewModel.setRelHeight(dragStartRelH - (viewModel.getRelY() - dragStartRelY));
+ break;
+ case RESIZE_BL:
+ viewModel.setRelX(clamp(dragStartRelX + dx, 0, dragStartRelX + dragStartRelW - 0.02));
+ viewModel.setRelWidth(dragStartRelW - (viewModel.getRelX() - dragStartRelX));
+ viewModel.setRelHeight(Math.max(0.02, dragStartRelH + dy));
+ break;
+ default:
+ break;
+ }
+ e.consume();
+ }
+
+ private void onMouseReleased(MouseEvent e) {
+ dragMode = DragMode.NONE;
+ e.consume();
+ }
+
+ private void onMouseMoved(MouseEvent e) {
+ if (!viewModel.isPlaced()) {
+ setCursor(Cursor.CROSSHAIR);
+ return;
+ }
+
+ DragMode handleMode = getHandleAt(e.getX(), e.getY());
+ switch (handleMode) {
+ case RESIZE_TL:
+ case RESIZE_BR:
+ setCursor(Cursor.NW_RESIZE);
+ break;
+ case RESIZE_TR:
+ case RESIZE_BL:
+ setCursor(Cursor.NE_RESIZE);
+ break;
+ default:
+ double w = getWidth();
+ double h = getHeight();
+ double rx = viewModel.getRelX() * w;
+ double ry = viewModel.getRelY() * h;
+ double rw = viewModel.getRelWidth() * w;
+ double rh = viewModel.getRelHeight() * h;
+ if (e.getX() >= rx && e.getX() <= rx + rw && e.getY() >= ry && e.getY() <= ry + rh) {
+ setCursor(Cursor.MOVE);
+ } else {
+ setCursor(Cursor.CROSSHAIR);
+ }
+ break;
+ }
+ }
+
+ private DragMode getHandleAt(double mx, double my) {
+ if (!viewModel.isPlaced()) return DragMode.NONE;
+ double tolerance = HANDLE_SIZE;
+ double w = getWidth();
+ double h = getHeight();
+ double rx = viewModel.getRelX() * w;
+ double ry = viewModel.getRelY() * h;
+ double rw = viewModel.getRelWidth() * w;
+ double rh = viewModel.getRelHeight() * h;
+
+ if (near(mx, my, rx, ry, tolerance)) return DragMode.RESIZE_TL;
+ if (near(mx, my, rx + rw, ry, tolerance)) return DragMode.RESIZE_TR;
+ if (near(mx, my, rx, ry + rh, tolerance)) return DragMode.RESIZE_BL;
+ if (near(mx, my, rx + rw, ry + rh, tolerance)) return DragMode.RESIZE_BR;
+ return DragMode.NONE;
+ }
+
+ private static boolean near(double x1, double y1, double x2, double y2, double tol) {
+ return Math.abs(x1 - x2) < tol && Math.abs(y1 - y2) < tol;
+ }
+
+ private static double clamp(double v, double min, double max) {
+ return Math.max(min, Math.min(max, v));
+ }
+}
diff --git a/jsignpdf/src/main/java/net/sf/jsignpdf/fx/service/KeyStoreService.java b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/service/KeyStoreService.java
new file mode 100644
index 00000000..38d9c824
--- /dev/null
+++ b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/service/KeyStoreService.java
@@ -0,0 +1,29 @@
+package net.sf.jsignpdf.fx.service;
+
+import javafx.concurrent.Service;
+import javafx.concurrent.Task;
+import net.sf.jsignpdf.BasicSignerOptions;
+import net.sf.jsignpdf.utils.KeyStoreUtils;
+
+/**
+ * Background service that loads key aliases from a keystore.
+ */
+public class KeyStoreService extends Service {
+
+ private BasicSignerOptions options;
+
+ public void setOptions(BasicSignerOptions options) {
+ this.options = options;
+ }
+
+ @Override
+ protected Task createTask() {
+ final BasicSignerOptions taskOptions = this.options;
+ return new Task() {
+ @Override
+ protected String[] call() {
+ return KeyStoreUtils.getKeyAliases(taskOptions);
+ }
+ };
+ }
+}
diff --git a/jsignpdf/src/main/java/net/sf/jsignpdf/fx/service/PdfRenderService.java b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/service/PdfRenderService.java
new file mode 100644
index 00000000..bcd5a1cc
--- /dev/null
+++ b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/service/PdfRenderService.java
@@ -0,0 +1,51 @@
+package net.sf.jsignpdf.fx.service;
+
+import java.awt.image.BufferedImage;
+
+import javafx.concurrent.Service;
+import javafx.concurrent.Task;
+import javafx.scene.image.Image;
+import net.sf.jsignpdf.BasicSignerOptions;
+import net.sf.jsignpdf.fx.util.SwingFxImageConverter;
+import net.sf.jsignpdf.preview.Pdf2Image;
+
+/**
+ * Background service that renders a PDF page to a JavaFX Image using the existing Pdf2Image class.
+ */
+public class PdfRenderService extends Service {
+
+ private BasicSignerOptions options;
+ private int page = 1;
+
+ public void setOptions(BasicSignerOptions options) {
+ this.options = options;
+ }
+
+ public void setPage(int page) {
+ this.page = page;
+ }
+
+ @Override
+ protected Task createTask() {
+ final BasicSignerOptions taskOptions = this.options;
+ final int taskPage = this.page;
+
+ return new Task() {
+ @Override
+ protected Image call() {
+ // JavaFX Service.cancel() interrupts the running thread. When the service is
+ // restarted (cancel → reset → start), the new task may inherit a stale interrupt
+ // flag on the thread because the FX executor can reuse the same pool thread.
+ // Pdf2Image uses blocking I/O (e.g., RandomAccessFile) that throws
+ // ClosedByInterruptException if the flag is set, causing the render to fail
+ // immediately. Clearing the flag here is safe: a "real" interrupt between
+ // cancel() and this point would only mean a redundant cancellation of an already-
+ // cancelled cycle — the next restart will set up a fresh task regardless.
+ Thread.interrupted();
+ Pdf2Image p2i = new Pdf2Image(taskOptions);
+ BufferedImage buffered = p2i.getImageForPage(taskPage);
+ return SwingFxImageConverter.toFxImage(buffered);
+ }
+ };
+ }
+}
diff --git a/jsignpdf/src/main/java/net/sf/jsignpdf/fx/service/SigningService.java b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/service/SigningService.java
new file mode 100644
index 00000000..98824db0
--- /dev/null
+++ b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/service/SigningService.java
@@ -0,0 +1,30 @@
+package net.sf.jsignpdf.fx.service;
+
+import javafx.concurrent.Service;
+import javafx.concurrent.Task;
+import net.sf.jsignpdf.BasicSignerOptions;
+import net.sf.jsignpdf.SignerLogic;
+
+/**
+ * Background service that wraps SignerLogic.signFile() for JavaFX.
+ */
+public class SigningService extends Service {
+
+ private BasicSignerOptions options;
+
+ public void setOptions(BasicSignerOptions options) {
+ this.options = options;
+ }
+
+ @Override
+ protected Task createTask() {
+ final BasicSignerOptions taskOptions = this.options;
+ return new Task() {
+ @Override
+ protected Boolean call() {
+ SignerLogic logic = new SignerLogic(taskOptions);
+ return logic.signFile();
+ }
+ };
+ }
+}
diff --git a/jsignpdf/src/main/java/net/sf/jsignpdf/fx/util/FxResourceProvider.java b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/util/FxResourceProvider.java
new file mode 100644
index 00000000..3a784a96
--- /dev/null
+++ b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/util/FxResourceProvider.java
@@ -0,0 +1,45 @@
+package net.sf.jsignpdf.fx.util;
+
+import javafx.beans.binding.StringBinding;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleObjectProperty;
+import net.sf.jsignpdf.Constants;
+import net.sf.jsignpdf.utils.ResourceProvider;
+
+/**
+ * Adapts ResourceProvider for JavaFX StringBindings,
+ * enabling easy binding of i18n strings to JavaFX UI properties.
+ */
+public final class FxResourceProvider {
+
+ private static final ResourceProvider RES = Constants.RES;
+
+ private FxResourceProvider() {
+ }
+
+ /**
+ * Get a localized string by key.
+ */
+ public static String get(String key) {
+ return RES.get(key);
+ }
+
+ /**
+ * Get a localized string with parameters.
+ */
+ public static String get(String key, String... args) {
+ return RES.get(key, args);
+ }
+
+ /**
+ * Create a StringBinding for a resource key.
+ */
+ public static StringBinding createStringBinding(String key) {
+ return new StringBinding() {
+ @Override
+ protected String computeValue() {
+ return RES.get(key);
+ }
+ };
+ }
+}
diff --git a/jsignpdf/src/main/java/net/sf/jsignpdf/fx/util/RecentFilesManager.java b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/util/RecentFilesManager.java
new file mode 100644
index 00000000..bd578112
--- /dev/null
+++ b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/util/RecentFilesManager.java
@@ -0,0 +1,49 @@
+package net.sf.jsignpdf.fx.util;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import net.sf.jsignpdf.Constants;
+import net.sf.jsignpdf.utils.PropertyProvider;
+
+/**
+ * Manages a list of recently opened PDF files, persisted via PropertyProvider.
+ */
+public class RecentFilesManager {
+
+ private static final int MAX_RECENT = 10;
+ private final PropertyProvider props = PropertyProvider.getInstance();
+
+ public void addFile(File file) {
+ List files = getRecentFiles();
+ String path = file.getAbsolutePath();
+ files.remove(path);
+ files.add(0, path);
+ while (files.size() > MAX_RECENT) {
+ files.remove(files.size() - 1);
+ }
+ saveFiles(files);
+ }
+
+ public List getRecentFiles() {
+ List result = new ArrayList<>();
+ for (int i = 0; i < MAX_RECENT; i++) {
+ String path = props.getProperty(Constants.PROPERTY_RECENT_FILE_PREFIX + i);
+ if (path != null && !path.isEmpty() && new File(path).exists()) {
+ result.add(path);
+ }
+ }
+ return result;
+ }
+
+ private void saveFiles(List files) {
+ for (int i = 0; i < MAX_RECENT; i++) {
+ if (i < files.size()) {
+ props.setProperty(Constants.PROPERTY_RECENT_FILE_PREFIX + i, files.get(i));
+ } else {
+ props.removeProperty(Constants.PROPERTY_RECENT_FILE_PREFIX + i);
+ }
+ }
+ }
+}
diff --git a/jsignpdf/src/main/java/net/sf/jsignpdf/fx/util/SwingFxImageConverter.java b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/util/SwingFxImageConverter.java
new file mode 100644
index 00000000..972b2088
--- /dev/null
+++ b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/util/SwingFxImageConverter.java
@@ -0,0 +1,22 @@
+package net.sf.jsignpdf.fx.util;
+
+import java.awt.image.BufferedImage;
+
+import javafx.embed.swing.SwingFXUtils;
+import javafx.scene.image.Image;
+
+/**
+ * Utility for converting between AWT BufferedImage and JavaFX Image.
+ */
+public final class SwingFxImageConverter {
+
+ private SwingFxImageConverter() {
+ }
+
+ public static Image toFxImage(BufferedImage bufferedImage) {
+ if (bufferedImage == null) {
+ return null;
+ }
+ return SwingFXUtils.toFXImage(bufferedImage, null);
+ }
+}
diff --git a/jsignpdf/src/main/java/net/sf/jsignpdf/fx/view/CertificateSettingsController.java b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/view/CertificateSettingsController.java
new file mode 100644
index 00000000..a5564ccd
--- /dev/null
+++ b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/view/CertificateSettingsController.java
@@ -0,0 +1,101 @@
+package net.sf.jsignpdf.fx.view;
+
+import java.io.File;
+import java.util.logging.Level;
+
+import javafx.collections.FXCollections;
+import javafx.fxml.FXML;
+import javafx.scene.control.Button;
+import javafx.scene.control.CheckBox;
+import javafx.scene.control.ComboBox;
+import javafx.scene.control.PasswordField;
+import javafx.scene.control.TextField;
+import javafx.stage.FileChooser;
+import net.sf.jsignpdf.BasicSignerOptions;
+import net.sf.jsignpdf.fx.service.KeyStoreService;
+import net.sf.jsignpdf.fx.viewmodel.SigningOptionsViewModel;
+import net.sf.jsignpdf.utils.KeyStoreUtils;
+
+import static net.sf.jsignpdf.Constants.LOGGER;
+import static net.sf.jsignpdf.Constants.RES;
+
+/**
+ * Controller for the certificate/keystore settings panel.
+ */
+public class CertificateSettingsController {
+
+ @FXML private ComboBox cmbKeystoreType;
+ @FXML private TextField txtKeystoreFile;
+ @FXML private Button btnBrowseKeystore;
+ @FXML private PasswordField txtKeystorePassword;
+ @FXML private Button btnLoadKeys;
+ @FXML private ComboBox cmbKeyAlias;
+ @FXML private PasswordField txtKeyPassword;
+ @FXML private CheckBox chkStorePasswords;
+
+ private SigningOptionsViewModel viewModel;
+ private final KeyStoreService keyStoreService = new KeyStoreService();
+
+ @FXML
+ private void initialize() {
+ // Populate keystore types
+ cmbKeystoreType.setItems(FXCollections.observableArrayList(KeyStoreUtils.getKeyStores()));
+
+ // Setup key loading service callbacks
+ keyStoreService.setOnSucceeded(e -> {
+ String[] aliases = keyStoreService.getValue();
+ cmbKeyAlias.setItems(FXCollections.observableArrayList(aliases));
+ if (aliases.length > 0) {
+ cmbKeyAlias.getSelectionModel().selectFirst();
+ }
+ });
+ keyStoreService.setOnFailed(e -> {
+ LOGGER.log(Level.WARNING, "Failed to load key aliases", keyStoreService.getException());
+ cmbKeyAlias.getItems().clear();
+ });
+ }
+
+ public void setViewModel(SigningOptionsViewModel vm) {
+ this.viewModel = vm;
+ bindToViewModel();
+ }
+
+ private void bindToViewModel() {
+ // Bidirectional bindings
+ cmbKeystoreType.valueProperty().bindBidirectional(viewModel.ksTypeProperty());
+ txtKeystoreFile.textProperty().bindBidirectional(viewModel.ksFileProperty());
+ txtKeystorePassword.textProperty().bindBidirectional(viewModel.ksPasswordProperty());
+ cmbKeyAlias.valueProperty().bindBidirectional(viewModel.keyAliasProperty());
+ txtKeyPassword.textProperty().bindBidirectional(viewModel.keyPasswordProperty());
+ chkStorePasswords.selectedProperty().bindBidirectional(viewModel.storePasswordsProperty());
+ }
+
+ @FXML
+ private void onBrowseKeystore() {
+ FileChooser fc = new FileChooser();
+ fc.setTitle(RES.get("jfx.gui.dialog.selectKeystoreFile"));
+ fc.getExtensionFilters().addAll(
+ new FileChooser.ExtensionFilter("All Files", "*.*"),
+ new FileChooser.ExtensionFilter("PKCS12", "*.p12", "*.pfx"),
+ new FileChooser.ExtensionFilter("JKS", "*.jks"));
+ File file = fc.showOpenDialog(txtKeystoreFile.getScene().getWindow());
+ if (file != null) {
+ txtKeystoreFile.setText(file.getAbsolutePath());
+ }
+ }
+
+ @FXML
+ private void onLoadKeys() {
+ // Create temporary options to load keys
+ BasicSignerOptions tmpOpts = new BasicSignerOptions();
+ tmpOpts.setKsType(cmbKeystoreType.getValue());
+ tmpOpts.setKsFile(txtKeystoreFile.getText());
+ tmpOpts.setKsPasswd(txtKeystorePassword.getText() != null
+ ? txtKeystorePassword.getText().toCharArray() : null);
+
+ keyStoreService.cancel();
+ keyStoreService.reset();
+ keyStoreService.setOptions(tmpOpts);
+ keyStoreService.start();
+ }
+}
diff --git a/jsignpdf/src/main/java/net/sf/jsignpdf/fx/view/EncryptionSettingsController.java b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/view/EncryptionSettingsController.java
new file mode 100644
index 00000000..b1e4f7ad
--- /dev/null
+++ b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/view/EncryptionSettingsController.java
@@ -0,0 +1,84 @@
+package net.sf.jsignpdf.fx.view;
+
+import java.io.File;
+
+import static net.sf.jsignpdf.Constants.RES;
+
+import javafx.collections.FXCollections;
+import javafx.fxml.FXML;
+import javafx.scene.control.CheckBox;
+import javafx.scene.control.ComboBox;
+import javafx.scene.control.PasswordField;
+import javafx.scene.control.TextField;
+import javafx.scene.layout.VBox;
+import javafx.stage.FileChooser;
+import net.sf.jsignpdf.fx.viewmodel.SigningOptionsViewModel;
+import net.sf.jsignpdf.types.PDFEncryption;
+import net.sf.jsignpdf.types.PrintRight;
+
+/**
+ * Controller for PDF encryption and rights settings.
+ */
+public class EncryptionSettingsController {
+
+ @FXML private ComboBox cmbEncryption;
+ @FXML private VBox encryptionDetailsPane;
+ @FXML private PasswordField txtOwnerPassword;
+ @FXML private PasswordField txtUserPassword;
+ @FXML private TextField txtEncCertFile;
+
+ // Rights
+ @FXML private ComboBox cmbPrintRight;
+ @FXML private CheckBox chkCopy;
+ @FXML private CheckBox chkAssembly;
+ @FXML private CheckBox chkFillIn;
+ @FXML private CheckBox chkScreenReaders;
+ @FXML private CheckBox chkModifyAnnotations;
+ @FXML private CheckBox chkModifyContents;
+
+ private SigningOptionsViewModel viewModel;
+
+ @FXML
+ private void initialize() {
+ cmbEncryption.setItems(FXCollections.observableArrayList(PDFEncryption.values()));
+ cmbPrintRight.setItems(FXCollections.observableArrayList(PrintRight.values()));
+
+ // Toggle encryption details visibility
+ cmbEncryption.valueProperty().addListener((obs, o, n) ->
+ encryptionDetailsPane.setVisible(n != null && n != PDFEncryption.NONE));
+ encryptionDetailsPane.setVisible(false);
+ encryptionDetailsPane.managedProperty().bind(encryptionDetailsPane.visibleProperty());
+ }
+
+ public void setViewModel(SigningOptionsViewModel vm) {
+ this.viewModel = vm;
+ bindToViewModel();
+ }
+
+ private void bindToViewModel() {
+ cmbEncryption.valueProperty().bindBidirectional(viewModel.pdfEncryptionProperty());
+ txtOwnerPassword.textProperty().bindBidirectional(viewModel.pdfOwnerPasswordProperty());
+ txtUserPassword.textProperty().bindBidirectional(viewModel.pdfUserPasswordProperty());
+ txtEncCertFile.textProperty().bindBidirectional(viewModel.pdfEncryptionCertFileProperty());
+
+ cmbPrintRight.valueProperty().bindBidirectional(viewModel.rightPrintingProperty());
+ chkCopy.selectedProperty().bindBidirectional(viewModel.rightCopyProperty());
+ chkAssembly.selectedProperty().bindBidirectional(viewModel.rightAssemblyProperty());
+ chkFillIn.selectedProperty().bindBidirectional(viewModel.rightFillInProperty());
+ chkScreenReaders.selectedProperty().bindBidirectional(viewModel.rightScreenReadersProperty());
+ chkModifyAnnotations.selectedProperty().bindBidirectional(viewModel.rightModifyAnnotationsProperty());
+ chkModifyContents.selectedProperty().bindBidirectional(viewModel.rightModifyContentsProperty());
+
+ // Update visibility from initial loaded values
+ PDFEncryption enc = viewModel.pdfEncryptionProperty().get();
+ encryptionDetailsPane.setVisible(enc != null && enc != PDFEncryption.NONE);
+ }
+
+ @FXML
+ private void onBrowseEncCert() {
+ FileChooser fc = new FileChooser();
+ fc.setTitle(RES.get("jfx.gui.dialog.selectEncryptionCert"));
+ File file = fc.showOpenDialog(txtEncCertFile.getScene().getWindow());
+ if (file != null) txtEncCertFile.setText(file.getAbsolutePath());
+ }
+}
diff --git a/jsignpdf/src/main/java/net/sf/jsignpdf/fx/view/MainWindowController.java b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/view/MainWindowController.java
new file mode 100644
index 00000000..87b1adfd
--- /dev/null
+++ b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/view/MainWindowController.java
@@ -0,0 +1,648 @@
+package net.sf.jsignpdf.fx.view;
+
+import java.io.File;
+import java.util.List;
+import java.util.logging.Level;
+
+import javafx.fxml.FXML;
+import javafx.scene.control.Alert;
+import javafx.scene.control.Button;
+import javafx.scene.control.ComboBox;
+import javafx.scene.control.Label;
+import javafx.scene.control.Menu;
+import javafx.scene.control.MenuItem;
+import javafx.scene.control.ProgressBar;
+import javafx.scene.control.ScrollPane;
+import javafx.scene.control.SplitPane;
+import javafx.scene.control.TextField;
+import javafx.scene.input.DragEvent;
+import javafx.scene.input.Dragboard;
+import javafx.scene.input.KeyCode;
+import javafx.scene.input.KeyEvent;
+import javafx.scene.input.TransferMode;
+import javafx.scene.layout.StackPane;
+import javafx.stage.FileChooser;
+import javafx.stage.Stage;
+import net.sf.jsignpdf.BasicSignerOptions;
+import net.sf.jsignpdf.Constants;
+import net.sf.jsignpdf.PdfExtraInfo;
+import javafx.scene.layout.VBox;
+import net.sf.jsignpdf.fx.control.PdfPageView;
+import net.sf.jsignpdf.fx.control.SignatureOverlay;
+import net.sf.jsignpdf.fx.service.PdfRenderService;
+import net.sf.jsignpdf.fx.service.SigningService;
+import net.sf.jsignpdf.fx.util.RecentFilesManager;
+import net.sf.jsignpdf.fx.viewmodel.DocumentViewModel;
+import net.sf.jsignpdf.fx.viewmodel.SignaturePlacementViewModel;
+import net.sf.jsignpdf.fx.viewmodel.SigningOptionsViewModel;
+import net.sf.jsignpdf.types.PageInfo;
+
+import static net.sf.jsignpdf.Constants.LOGGER;
+import static net.sf.jsignpdf.Constants.RES;
+
+/**
+ * Controller for the main application window.
+ */
+public class MainWindowController {
+
+ private Stage stage;
+ private BasicSignerOptions options;
+ private final DocumentViewModel documentVM = new DocumentViewModel();
+ private final SigningOptionsViewModel signingVM = new SigningOptionsViewModel();
+ private final SignaturePlacementViewModel placementVM = new SignaturePlacementViewModel();
+ private final PdfRenderService renderService = new PdfRenderService();
+ private final SigningService signingService = new SigningService();
+ private final RecentFilesManager recentFilesManager = new RecentFilesManager();
+ private PdfPageView pdfPageView;
+ private SignatureOverlay signatureOverlay;
+
+ // Included sub-controllers (fx:id + "Controller" naming convention)
+ @FXML private VBox certificateSettings;
+ @FXML private CertificateSettingsController certificateSettingsController;
+ @FXML private VBox signatureSettings;
+ @FXML private SignatureSettingsController signatureSettingsController;
+ @FXML private VBox tsaSettings;
+ @FXML private TsaSettingsController tsaSettingsController;
+ @FXML private VBox encryptionSettings;
+ @FXML private EncryptionSettingsController encryptionSettingsController;
+ @FXML private VBox outputConsole;
+ @FXML private OutputConsoleController outputConsoleController;
+
+ // Menu items
+ @FXML private MenuItem menuOpen;
+ @FXML private MenuItem menuClose;
+ @FXML private Menu menuRecentFiles;
+ @FXML private MenuItem menuSign;
+ @FXML private MenuItem menuExit;
+ @FXML private MenuItem menuZoomIn;
+ @FXML private MenuItem menuZoomOut;
+ @FXML private MenuItem menuZoomFit;
+ @FXML private MenuItem menuToggleSidePanel;
+ @FXML private MenuItem menuAbout;
+
+ // Toolbar
+ @FXML private Button btnOpen;
+ @FXML private Button btnZoomIn;
+ @FXML private Button btnZoomOut;
+ @FXML private Button btnZoomFit;
+ @FXML private ComboBox cmbZoom;
+ @FXML private Button btnPrevPage;
+ @FXML private TextField txtPageNumber;
+ @FXML private Label lblPageCount;
+ @FXML private Button btnNextPage;
+ @FXML private Button btnSign;
+
+ // Content area
+ @FXML private SplitPane splitPane;
+ @FXML private ScrollPane scrollPane;
+ @FXML private StackPane pdfArea;
+ @FXML private Label lblDropHint;
+
+ // Status bar
+ @FXML private Label lblStatus;
+ @FXML private ProgressBar progressBar;
+
+ public void setStage(Stage stage) {
+ this.stage = stage;
+ stage.addEventFilter(KeyEvent.KEY_PRESSED, this::handleKeyPress);
+ }
+
+ /**
+ * Initializes the UI from persisted BasicSignerOptions (called after loadOptions()).
+ * Populates all ViewModel properties from the options so the UI is prefilled.
+ */
+ public void initFromOptions(BasicSignerOptions opts) {
+ this.options = opts;
+ signingVM.syncFromOptions(opts);
+ }
+
+ /**
+ * Stores current UI state to BasicSignerOptions and persists to disk.
+ * Called on window close.
+ */
+ public void storeAndCleanup() {
+ try {
+ if (options == null) {
+ options = new BasicSignerOptions();
+ }
+
+ // Sync placement rectangle coordinates to the signing ViewModel before persisting
+ if (placementVM.isPlaced() && documentVM.isDocumentLoaded()) {
+ signingVM.visibleProperty().set(true);
+ signingVM.pageProperty().set(documentVM.getCurrentPage());
+
+ PdfExtraInfo extraInfo = new PdfExtraInfo(options);
+ PageInfo pageInfo = extraInfo.getPageInfo(documentVM.getCurrentPage());
+ if (pageInfo != null) {
+ float[] coords = placementVM.toPdfCoordinates(
+ pageInfo.getWidth(), pageInfo.getHeight());
+ signingVM.positionLLXProperty().set(coords[0]);
+ signingVM.positionLLYProperty().set(coords[1]);
+ signingVM.positionURXProperty().set(coords[2]);
+ signingVM.positionURYProperty().set(coords[3]);
+ }
+ }
+
+ signingVM.syncToOptions(options);
+ options.storeOptions();
+ } catch (Exception e) {
+ LOGGER.log(Level.WARNING, "Failed to store options", e);
+ }
+ if (outputConsoleController != null) {
+ outputConsoleController.dispose();
+ }
+ }
+
+ @FXML
+ private void initialize() {
+ // Wire sub-controllers
+ if (certificateSettingsController != null) {
+ certificateSettingsController.setViewModel(signingVM);
+ }
+ if (signatureSettingsController != null) {
+ signatureSettingsController.setViewModel(signingVM);
+ }
+ if (tsaSettingsController != null) {
+ tsaSettingsController.setViewModel(signingVM);
+ }
+ if (encryptionSettingsController != null) {
+ encryptionSettingsController.setViewModel(signingVM);
+ }
+
+ // Setup PDF page view and signature overlay
+ pdfPageView = new PdfPageView();
+ pdfPageView.setVisible(false);
+ signatureOverlay = new SignatureOverlay(placementVM);
+ signatureOverlay.setVisible(false);
+ signatureOverlay.setMouseTransparent(false);
+ pdfArea.getChildren().add(0, pdfPageView);
+ pdfArea.getChildren().add(1, signatureOverlay);
+
+ // Bind pdfArea min size to pdfPageView so scrollbars appear when the page
+ // exceeds the viewport. With fitToWidth/fitToHeight on the ScrollPane, the
+ // StackPane expands to fill the viewport (centering children) but minSize
+ // prevents it from shrinking below the rendered page, triggering scrollbars.
+ pdfArea.minWidthProperty().bind(pdfPageView.prefWidthProperty());
+ pdfArea.minHeightProperty().bind(pdfPageView.prefHeightProperty());
+
+ // Auto-enable visible signature when a rectangle is placed
+ placementVM.placedProperty().addListener((obs, wasPlaced, isPlaced) -> {
+ if (isPlaced) {
+ signingVM.visibleProperty().set(true);
+ }
+ updateStatusWithHint();
+ });
+
+ // Clear placement rectangle when visible signature is disabled
+ signingVM.visibleProperty().addListener((obs, wasVisible, isVisible) -> {
+ if (!isVisible) {
+ placementVM.reset();
+ }
+ });
+
+ // Keep overlay sized to match the pdf page view
+ signatureOverlay.prefWidthProperty().bind(pdfPageView.prefWidthProperty());
+ signatureOverlay.prefHeightProperty().bind(pdfPageView.prefHeightProperty());
+ signatureOverlay.minWidthProperty().bind(pdfPageView.minWidthProperty());
+ signatureOverlay.minHeightProperty().bind(pdfPageView.minHeightProperty());
+ signatureOverlay.maxWidthProperty().bind(pdfPageView.maxWidthProperty());
+ signatureOverlay.maxHeightProperty().bind(pdfPageView.maxHeightProperty());
+
+ progressBar.setVisible(false);
+ updateStatus(RES.get("jfx.gui.status.ready"));
+
+ cmbZoom.getItems().addAll("50%", "75%", "100%", "125%", "150%", "200%");
+ cmbZoom.setValue("100%");
+
+ // Disable controls that require a loaded document
+ setDocumentControlsDisabled(true);
+
+ // Bind PDF page view to ViewModel
+ pdfPageView.pageImageProperty().bind(documentVM.currentPageImageProperty());
+ pdfPageView.zoomLevelProperty().bind(documentVM.zoomLevelProperty());
+
+ // Listen for page changes to trigger re-render
+ documentVM.currentPageProperty().addListener((obs, oldVal, newVal) -> {
+ txtPageNumber.setText(String.valueOf(newVal.intValue()));
+ renderCurrentPage();
+ updateNavButtonState();
+ });
+
+ // Zoom combo box changes
+ cmbZoom.setOnAction(e -> {
+ String val = cmbZoom.getValue();
+ if (val != null) {
+ try {
+ double zoom = Double.parseDouble(val.replace("%", "").trim()) / 100.0;
+ documentVM.setZoomLevel(zoom);
+ } catch (NumberFormatException ignored) {
+ }
+ }
+ });
+
+ // Zoom level changes update combo
+ documentVM.zoomLevelProperty().addListener((obs, oldVal, newVal) -> {
+ String formatted = Math.round(newVal.doubleValue() * 100) + "%";
+ if (!formatted.equals(cmbZoom.getValue())) {
+ cmbZoom.setValue(formatted);
+ }
+ });
+
+ // Page number text field commit
+ txtPageNumber.setOnAction(e -> {
+ try {
+ int page = Integer.parseInt(txtPageNumber.getText().trim());
+ documentVM.setCurrentPage(page);
+ } catch (NumberFormatException ignored) {
+ txtPageNumber.setText(String.valueOf(documentVM.getCurrentPage()));
+ }
+ });
+
+ // Setup render service callbacks
+ renderService.setOnSucceeded(e -> {
+ documentVM.setCurrentPageImage(renderService.getValue());
+ pdfPageView.setVisible(true);
+ progressBar.setVisible(false);
+ updateStatusForDocument();
+ });
+ renderService.setOnFailed(e -> {
+ LOGGER.log(Level.WARNING, "Failed to render page", renderService.getException());
+ progressBar.setVisible(false);
+ updateStatus(RES.get("jfx.gui.status.renderError"));
+ });
+
+ // Signing service callbacks
+ signingService.setOnSucceeded(e -> {
+ progressBar.setVisible(false);
+ boolean success = signingService.getValue();
+ if (success) {
+ updateStatus(RES.get("jfx.gui.status.signingOk"));
+ showAlert(Alert.AlertType.INFORMATION,
+ RES.get("jfx.gui.dialog.signingComplete.title"),
+ RES.get("jfx.gui.dialog.signingComplete.text"));
+ } else {
+ updateStatus(RES.get("jfx.gui.status.signingFailed"));
+ showAlert(Alert.AlertType.ERROR,
+ RES.get("jfx.gui.dialog.signingFailed.title"),
+ RES.get("jfx.gui.dialog.signingFailed.text"));
+ }
+ });
+ signingService.setOnFailed(e -> {
+ progressBar.setVisible(false);
+ LOGGER.log(Level.SEVERE, "Signing service error", signingService.getException());
+ updateStatus(RES.get("jfx.gui.status.signingFailed") + ": "
+ + signingService.getException().getMessage());
+ showAlert(Alert.AlertType.ERROR,
+ RES.get("jfx.gui.dialog.signingError.title"),
+ signingService.getException().getMessage());
+ });
+
+ refreshRecentFilesMenu();
+ }
+
+ private void refreshRecentFilesMenu() {
+ menuRecentFiles.getItems().clear();
+ List recentFiles = recentFilesManager.getRecentFiles();
+ if (recentFiles.isEmpty()) {
+ MenuItem empty = new MenuItem(RES.get("jfx.gui.menu.file.recentFiles.empty"));
+ empty.setDisable(true);
+ menuRecentFiles.getItems().add(empty);
+ } else {
+ for (String path : recentFiles) {
+ MenuItem item = new MenuItem(path);
+ item.setMnemonicParsing(false);
+ item.setOnAction(e -> openDocument(new File(path)));
+ menuRecentFiles.getItems().add(item);
+ }
+ }
+ }
+
+ private void setDocumentControlsDisabled(boolean disabled) {
+ btnZoomIn.setDisable(disabled);
+ btnZoomOut.setDisable(disabled);
+ btnZoomFit.setDisable(disabled);
+ cmbZoom.setDisable(disabled);
+ btnPrevPage.setDisable(disabled);
+ txtPageNumber.setDisable(disabled);
+ btnNextPage.setDisable(disabled);
+ btnSign.setDisable(disabled);
+ menuSign.setDisable(disabled);
+ menuClose.setDisable(disabled);
+ menuZoomIn.setDisable(disabled);
+ menuZoomOut.setDisable(disabled);
+ menuZoomFit.setDisable(disabled);
+ }
+
+ private void updateNavButtonState() {
+ btnPrevPage.setDisable(!documentVM.canGoPrev());
+ btnNextPage.setDisable(!documentVM.canGoNext());
+ }
+
+ private void updateStatus(String message) {
+ lblStatus.setText(message);
+ }
+
+ private void updateStatusForDocument() {
+ File file = documentVM.getDocumentFile();
+ if (file != null) {
+ updateStatus(file.getName() + " - Page " + documentVM.getCurrentPage()
+ + "/" + documentVM.getPageCount());
+ }
+ }
+
+ private void updateStatusWithHint() {
+ if (documentVM.isDocumentLoaded() && placementVM.isPlaced()) {
+ updateStatus(RES.get("jfx.gui.status.shiftToReplace"));
+ } else if (documentVM.isDocumentLoaded()) {
+ updateStatusForDocument();
+ }
+ }
+
+ private void renderCurrentPage() {
+ if (options == null || !documentVM.isDocumentLoaded()) {
+ return;
+ }
+ renderService.cancel();
+ renderService.reset();
+ renderService.setOptions(options);
+ renderService.setPage(documentVM.getCurrentPage());
+ progressBar.setVisible(true);
+ renderService.start();
+ }
+
+ // --- Keyboard handling ---
+ private void handleKeyPress(KeyEvent event) {
+ if (!documentVM.isDocumentLoaded()) return;
+ if (event.getCode() == KeyCode.PAGE_DOWN) {
+ documentVM.nextPage();
+ event.consume();
+ } else if (event.getCode() == KeyCode.PAGE_UP) {
+ documentVM.prevPage();
+ event.consume();
+ } else if (event.getCode() == KeyCode.Z && event.isShortcutDown() && placementVM.isPlaced()) {
+ placementVM.reset();
+ event.consume();
+ }
+ }
+
+ // --- Menu handlers ---
+
+ @FXML
+ private void onFileOpen() {
+ FileChooser fileChooser = new FileChooser();
+ fileChooser.setTitle(RES.get("jfx.gui.dialog.openPdf.title"));
+ fileChooser.getExtensionFilters().add(
+ new FileChooser.ExtensionFilter("PDF Files", "*.pdf"));
+ File file = fileChooser.showOpenDialog(stage);
+ if (file != null) {
+ openDocument(file);
+ }
+ }
+
+ @FXML
+ private void onFileClose() {
+ closeDocument();
+ }
+
+ @FXML
+ private void onFileExit() {
+ stage.close();
+ }
+
+ @FXML
+ private void onSign() {
+ if (options == null || !documentVM.isDocumentLoaded()) {
+ showAlert(Alert.AlertType.WARNING,
+ RES.get("jfx.gui.dialog.noDocument.title"),
+ RES.get("jfx.gui.dialog.noDocument.text"));
+ return;
+ }
+
+ // Sync ViewModel to options
+ signingVM.syncToOptions(options);
+
+ // Apply signature placement coordinates if placed
+ if (placementVM.isPlaced()) {
+ options.setVisible(true);
+ options.setPage(documentVM.getCurrentPage());
+
+ PdfExtraInfo extraInfo = new PdfExtraInfo(options);
+ PageInfo pageInfo = extraInfo.getPageInfo(documentVM.getCurrentPage());
+ if (pageInfo != null) {
+ float[] coords = placementVM.toPdfCoordinates(
+ pageInfo.getWidth(), pageInfo.getHeight());
+ options.setPositionLLX(coords[0]);
+ options.setPositionLLY(coords[1]);
+ options.setPositionURX(coords[2]);
+ options.setPositionURY(coords[3]);
+ }
+ }
+
+ // Generate output file name if not set
+ if (options.getOutFile() == null || options.getOutFile().isEmpty()) {
+ String inFile = options.getInFile();
+ String suffix = ".pdf";
+ String nameBase = inFile;
+ if (inFile.toLowerCase().endsWith(suffix)) {
+ nameBase = inFile.substring(0, inFile.length() - 4);
+ suffix = inFile.substring(inFile.length() - 4);
+ }
+ options.setOutFile(nameBase + Constants.DEFAULT_OUT_SUFFIX + suffix);
+ }
+
+ // Start signing
+ signingService.cancel();
+ signingService.reset();
+ signingService.setOptions(options.createCopy());
+ progressBar.setVisible(true);
+ progressBar.setProgress(-1); // indeterminate
+ updateStatus(RES.get("jfx.gui.status.signingInProgress"));
+ signingService.start();
+ }
+
+ @FXML
+ private void onZoomIn() {
+ documentVM.zoomIn();
+ }
+
+ @FXML
+ private void onZoomOut() {
+ documentVM.zoomOut();
+ }
+
+ @FXML
+ private void onZoomFit() {
+ if (!documentVM.isDocumentLoaded() || documentVM.getCurrentPageImage() == null) return;
+ double imgWidth = documentVM.getCurrentPageImage().getWidth();
+ double viewWidth = scrollPane.getViewportBounds().getWidth();
+ if (imgWidth > 0 && viewWidth > 0) {
+ documentVM.setZoomLevel(viewWidth / imgWidth);
+ }
+ }
+
+ @FXML
+ private void onPrevPage() {
+ documentVM.prevPage();
+ }
+
+ @FXML
+ private void onNextPage() {
+ documentVM.nextPage();
+ }
+
+ @FXML
+ private void onToggleSidePanel() {
+ if (splitPane.getItems().size() > 1) {
+ // Toggle visibility of side panel by manipulating divider position
+ double pos = splitPane.getDividerPositions()[0];
+ if (pos < 0.05) {
+ splitPane.setDividerPositions(0.28);
+ } else {
+ splitPane.setDividerPositions(0.0);
+ }
+ }
+ }
+
+ @FXML
+ private void onAbout() {
+ Alert alert = new Alert(Alert.AlertType.INFORMATION);
+ alert.setTitle(RES.get("jfx.gui.menu.help.about"));
+ alert.setHeaderText("JSignPdf " + Constants.VERSION);
+ alert.setContentText(RES.get("jfx.gui.dialog.about.description"));
+ alert.showAndWait();
+ }
+
+ // --- Drag and drop ---
+
+ @FXML
+ private void onDragOver(DragEvent event) {
+ Dragboard db = event.getDragboard();
+ if (db.hasFiles()) {
+ List files = db.getFiles();
+ if (files.size() == 1 && files.get(0).getName().toLowerCase().endsWith(".pdf")) {
+ event.acceptTransferModes(TransferMode.COPY);
+ }
+ }
+ event.consume();
+ }
+
+ @FXML
+ private void onDragDropped(DragEvent event) {
+ Dragboard db = event.getDragboard();
+ boolean success = false;
+ if (db.hasFiles()) {
+ List files = db.getFiles();
+ if (files.size() == 1 && files.get(0).getName().toLowerCase().endsWith(".pdf")) {
+ openDocument(files.get(0));
+ success = true;
+ }
+ }
+ event.setDropCompleted(success);
+ event.consume();
+ }
+
+ // --- Document handling ---
+
+ private void openDocument(File file) {
+ try {
+ if (options == null) {
+ options = new BasicSignerOptions();
+ options.loadOptions();
+ signingVM.syncFromOptions(options);
+ }
+
+ // Reset visible signature and placement from previous document
+ signingVM.visibleProperty().set(false);
+ placementVM.reset();
+
+ options.setInFile(file.getAbsolutePath());
+
+ // Get page count
+ PdfExtraInfo extraInfo = new PdfExtraInfo(options);
+ int pages = extraInfo.getNumberOfPages();
+ if (pages < 1) {
+ updateStatus(RES.get("jfx.gui.status.readError"));
+ return;
+ }
+
+ documentVM.setDocumentFile(file);
+ documentVM.setPageCount(pages);
+ documentVM.setZoomLevel(1.0);
+
+ lblDropHint.setVisible(false);
+ setDocumentControlsDisabled(false);
+ lblPageCount.setText("/ " + pages);
+ txtPageNumber.setText("1");
+ cmbZoom.setValue("100%");
+
+ stage.setTitle("JSignPdf " + Constants.VERSION + " - " + file.getName());
+ LOGGER.info("Opened document: " + file.getAbsolutePath());
+
+ recentFilesManager.addFile(file);
+ refreshRecentFilesMenu();
+
+ // Show signature overlay and render first page
+ signatureOverlay.setVisible(true);
+ documentVM.setCurrentPage(1);
+ renderCurrentPage();
+ updateNavButtonState();
+ } catch (Exception e) {
+ LOGGER.log(Level.SEVERE, "Failed to open document", e);
+ updateStatus("Error: " + e.getMessage());
+ }
+ }
+
+ private void closeDocument() {
+ renderService.cancel();
+ signingVM.visibleProperty().set(false);
+ documentVM.reset();
+ placementVM.reset();
+ signatureOverlay.setVisible(false);
+ if (options != null) {
+ options.setInFile(null);
+ }
+ pdfPageView.setVisible(false);
+ lblDropHint.setVisible(true);
+ setDocumentControlsDisabled(true);
+ lblPageCount.setText("/ 0");
+ txtPageNumber.setText("");
+ updateStatus(RES.get("jfx.gui.status.ready"));
+ stage.setTitle("JSignPdf " + Constants.VERSION);
+ }
+
+ /**
+ * Returns the document view model (used by other controllers).
+ */
+ public DocumentViewModel getDocumentViewModel() {
+ return documentVM;
+ }
+
+ private void showAlert(Alert.AlertType type, String title, String content) {
+ Alert alert = new Alert(type);
+ alert.setTitle(title);
+ alert.setHeaderText(null);
+ alert.setContentText(content);
+ alert.showAndWait();
+ }
+
+ /**
+ * Returns the signature placement view model.
+ */
+ public SignaturePlacementViewModel getPlacementViewModel() {
+ return placementVM;
+ }
+
+ /**
+ * Returns the signing options view model.
+ */
+ public SigningOptionsViewModel getSigningOptionsViewModel() {
+ return signingVM;
+ }
+
+ /**
+ * Returns the current signer options (used by other controllers).
+ */
+ public BasicSignerOptions getOptions() {
+ return options;
+ }
+}
diff --git a/jsignpdf/src/main/java/net/sf/jsignpdf/fx/view/OutputConsoleController.java b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/view/OutputConsoleController.java
new file mode 100644
index 00000000..9e6b9d24
--- /dev/null
+++ b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/view/OutputConsoleController.java
@@ -0,0 +1,79 @@
+package net.sf.jsignpdf.fx.view;
+
+import javafx.application.Platform;
+import javafx.fxml.FXML;
+import javafx.scene.control.TextArea;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+import static net.sf.jsignpdf.Constants.LOGGER;
+
+/**
+ * Controller for the output console panel that captures log messages.
+ */
+public class OutputConsoleController {
+
+ @FXML private TextArea txtOutput;
+
+ private Handler logHandler;
+
+ @FXML
+ private void initialize() {
+ // Remove any previously registered handler (guards against FXML reload leaks)
+ dispose();
+
+ // Attach a log handler to capture signing output
+ logHandler = new Handler() {
+ @Override
+ public void publish(LogRecord record) {
+ if (record == null) return;
+ StringBuilder sb = new StringBuilder();
+ if (record.getLevel() != null
+ && record.getLevel().intValue() >= Level.WARNING.intValue()) {
+ sb.append(record.getLevel().getName()).append(" ");
+ }
+ if (record.getMessage() != null) {
+ sb.append(record.getMessage());
+ }
+ if (record.getThrown() != null) {
+ sb.append("\n");
+ StringWriter sw = new StringWriter();
+ record.getThrown().printStackTrace(new PrintWriter(sw));
+ sb.append(sw);
+ }
+ if (sb.length() > 0) {
+ Platform.runLater(() -> txtOutput.appendText(sb.toString() + "\n"));
+ }
+ }
+
+ @Override
+ public void flush() {
+ }
+
+ @Override
+ public void close() {
+ }
+ };
+ LOGGER.addHandler(logHandler);
+ }
+
+ @FXML
+ private void onClear() {
+ txtOutput.clear();
+ }
+
+ public void dispose() {
+ if (logHandler != null) {
+ LOGGER.removeHandler(logHandler);
+ logHandler = null;
+ }
+ }
+
+ public void appendMessage(String message) {
+ Platform.runLater(() -> txtOutput.appendText(message + "\n"));
+ }
+}
diff --git a/jsignpdf/src/main/java/net/sf/jsignpdf/fx/view/SignatureSettingsController.java b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/view/SignatureSettingsController.java
new file mode 100644
index 00000000..21f1ae12
--- /dev/null
+++ b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/view/SignatureSettingsController.java
@@ -0,0 +1,122 @@
+package net.sf.jsignpdf.fx.view;
+
+import java.io.File;
+
+import static net.sf.jsignpdf.Constants.RES;
+
+import javafx.collections.FXCollections;
+import javafx.fxml.FXML;
+import javafx.scene.control.CheckBox;
+import javafx.scene.control.ComboBox;
+import javafx.scene.control.TextField;
+import javafx.scene.layout.VBox;
+import javafx.stage.FileChooser;
+import net.sf.jsignpdf.fx.viewmodel.SigningOptionsViewModel;
+import net.sf.jsignpdf.types.CertificationLevel;
+import net.sf.jsignpdf.types.HashAlgorithm;
+import net.sf.jsignpdf.types.RenderMode;
+
+/**
+ * Controller for signature appearance and metadata settings.
+ */
+public class SignatureSettingsController {
+
+ @FXML private CheckBox chkVisibleSig;
+ @FXML private VBox visibleSigPane;
+ @FXML private ComboBox cmbRenderMode;
+ @FXML private ComboBox cmbHashAlgorithm;
+ @FXML private ComboBox cmbCertLevel;
+ @FXML private TextField txtSignerName;
+ @FXML private TextField txtReason;
+ @FXML private TextField txtLocation;
+ @FXML private TextField txtContact;
+ @FXML private TextField txtL2Text;
+ @FXML private TextField txtL4Text;
+ @FXML private TextField txtFontSize;
+ @FXML private TextField txtImgPath;
+ @FXML private TextField txtBgImgPath;
+ @FXML private CheckBox chkAcro6Layers;
+ @FXML private CheckBox chkAppend;
+ @FXML private TextField txtOutFile;
+
+ private SigningOptionsViewModel viewModel;
+
+ @FXML
+ private void initialize() {
+ cmbRenderMode.setItems(FXCollections.observableArrayList(RenderMode.values()));
+ cmbHashAlgorithm.setItems(FXCollections.observableArrayList(HashAlgorithm.values()));
+ cmbCertLevel.setItems(FXCollections.observableArrayList(CertificationLevel.values()));
+
+ // Toggle visible signature details
+ visibleSigPane.managedProperty().bind(visibleSigPane.visibleProperty());
+ chkVisibleSig.selectedProperty().addListener((obs, o, n) ->
+ visibleSigPane.setVisible(n));
+ visibleSigPane.setVisible(false);
+ }
+
+ public void setViewModel(SigningOptionsViewModel vm) {
+ this.viewModel = vm;
+ bindToViewModel();
+ }
+
+ private void bindToViewModel() {
+ chkVisibleSig.selectedProperty().bindBidirectional(viewModel.visibleProperty());
+ cmbRenderMode.valueProperty().bindBidirectional(viewModel.renderModeProperty());
+ cmbHashAlgorithm.valueProperty().bindBidirectional(viewModel.hashAlgorithmProperty());
+ cmbCertLevel.valueProperty().bindBidirectional(viewModel.certLevelProperty());
+ txtSignerName.textProperty().bindBidirectional(viewModel.signerNameProperty());
+ txtReason.textProperty().bindBidirectional(viewModel.reasonProperty());
+ txtLocation.textProperty().bindBidirectional(viewModel.locationProperty());
+ txtContact.textProperty().bindBidirectional(viewModel.contactProperty());
+ txtL2Text.textProperty().bindBidirectional(viewModel.l2TextProperty());
+ txtL4Text.textProperty().bindBidirectional(viewModel.l4TextProperty());
+ txtImgPath.textProperty().bindBidirectional(viewModel.imgPathProperty());
+ txtBgImgPath.textProperty().bindBidirectional(viewModel.bgImgPathProperty());
+ chkAcro6Layers.selectedProperty().bindBidirectional(viewModel.acro6LayersProperty());
+ chkAppend.selectedProperty().bindBidirectional(viewModel.appendProperty());
+ txtOutFile.textProperty().bindBidirectional(viewModel.outFileProperty());
+
+ // Font size needs manual sync (String <-> float)
+ viewModel.l2TextFontSizeProperty().addListener((obs, o, n) ->
+ txtFontSize.setText(String.valueOf(n.floatValue())));
+ txtFontSize.setOnAction(e -> {
+ try {
+ viewModel.l2TextFontSizeProperty().set(Float.parseFloat(txtFontSize.getText()));
+ } catch (NumberFormatException ignored) {
+ }
+ });
+
+ // Update visibility from initial value
+ visibleSigPane.setVisible(viewModel.visibleProperty().get());
+ }
+
+ @FXML
+ private void onBrowseImage() {
+ File file = browseImageFile(RES.get("jfx.gui.dialog.selectSignatureImage"));
+ if (file != null) txtImgPath.setText(file.getAbsolutePath());
+ }
+
+ @FXML
+ private void onBrowseBgImage() {
+ File file = browseImageFile(RES.get("jfx.gui.dialog.selectBackgroundImage"));
+ if (file != null) txtBgImgPath.setText(file.getAbsolutePath());
+ }
+
+ @FXML
+ private void onBrowseOutFile() {
+ FileChooser fc = new FileChooser();
+ fc.setTitle(RES.get("jfx.gui.dialog.selectOutputPdf"));
+ fc.getExtensionFilters().add(new FileChooser.ExtensionFilter("PDF Files", "*.pdf"));
+ File file = fc.showSaveDialog(txtOutFile.getScene().getWindow());
+ if (file != null) txtOutFile.setText(file.getAbsolutePath());
+ }
+
+ private File browseImageFile(String title) {
+ FileChooser fc = new FileChooser();
+ fc.setTitle(title);
+ fc.getExtensionFilters().addAll(
+ new FileChooser.ExtensionFilter("Image Files", "*.png", "*.jpg", "*.jpeg", "*.gif"),
+ new FileChooser.ExtensionFilter("All Files", "*.*"));
+ return fc.showOpenDialog(txtImgPath.getScene().getWindow());
+ }
+}
diff --git a/jsignpdf/src/main/java/net/sf/jsignpdf/fx/view/TsaSettingsController.java b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/view/TsaSettingsController.java
new file mode 100644
index 00000000..2891c5bf
--- /dev/null
+++ b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/view/TsaSettingsController.java
@@ -0,0 +1,156 @@
+package net.sf.jsignpdf.fx.view;
+
+import java.io.File;
+
+import static net.sf.jsignpdf.Constants.RES;
+
+import javafx.collections.FXCollections;
+import javafx.fxml.FXML;
+import javafx.scene.control.CheckBox;
+import javafx.scene.control.ComboBox;
+import javafx.scene.control.Label;
+import javafx.scene.control.PasswordField;
+import javafx.scene.control.TextField;
+import javafx.scene.layout.VBox;
+import javafx.stage.FileChooser;
+import net.sf.jsignpdf.fx.viewmodel.SigningOptionsViewModel;
+import net.sf.jsignpdf.types.ServerAuthentication;
+
+import java.net.Proxy;
+
+/**
+ * Controller for TSA, OCSP, CRL, and proxy settings.
+ */
+public class TsaSettingsController {
+
+ @FXML private CheckBox chkTsaEnabled;
+ @FXML private TextField txtTsaUrl;
+ @FXML private ComboBox cmbTsaAuthn;
+ @FXML private TextField txtTsaUser;
+ @FXML private PasswordField txtTsaPassword;
+ @FXML private TextField txtTsaCertFileType;
+ @FXML private TextField txtTsaCertFile;
+ @FXML private PasswordField txtTsaCertFilePassword;
+ @FXML private TextField txtTsaPolicy;
+ @FXML private TextField txtTsaHashAlg;
+ @FXML private VBox tsaDetailsPane;
+
+ @FXML private CheckBox chkOcspEnabled;
+ @FXML private Label lblOcspServerUrl;
+ @FXML private TextField txtOcspServerUrl;
+ @FXML private CheckBox chkCrlEnabled;
+
+ @FXML private ComboBox cmbProxyType;
+ @FXML private Label lblProxyHost;
+ @FXML private TextField txtProxyHost;
+ @FXML private Label lblProxyPort;
+ @FXML private TextField txtProxyPort;
+
+ private SigningOptionsViewModel viewModel;
+
+ @FXML
+ private void initialize() {
+ cmbTsaAuthn.setItems(FXCollections.observableArrayList(ServerAuthentication.values()));
+ cmbProxyType.setItems(FXCollections.observableArrayList(Proxy.Type.values()));
+
+ // Toggle TSA details visibility
+ tsaDetailsPane.managedProperty().bind(tsaDetailsPane.visibleProperty());
+ chkTsaEnabled.selectedProperty().addListener((obs, o, n) ->
+ tsaDetailsPane.setVisible(n));
+ tsaDetailsPane.setVisible(false);
+
+ // Toggle OCSP URL visibility
+ chkOcspEnabled.selectedProperty().addListener((obs, o, n) -> {
+ lblOcspServerUrl.setVisible(n);
+ txtOcspServerUrl.setVisible(n);
+ lblOcspServerUrl.setManaged(n);
+ txtOcspServerUrl.setManaged(n);
+ });
+ lblOcspServerUrl.setVisible(false);
+ txtOcspServerUrl.setVisible(false);
+ lblOcspServerUrl.setManaged(false);
+ txtOcspServerUrl.setManaged(false);
+
+ // Toggle proxy details visibility
+ cmbProxyType.valueProperty().addListener((obs, o, n) -> {
+ boolean showDetails = n != null && n != Proxy.Type.DIRECT;
+ lblProxyHost.setVisible(showDetails);
+ txtProxyHost.setVisible(showDetails);
+ lblProxyPort.setVisible(showDetails);
+ txtProxyPort.setVisible(showDetails);
+ lblProxyHost.setManaged(showDetails);
+ txtProxyHost.setManaged(showDetails);
+ lblProxyPort.setManaged(showDetails);
+ txtProxyPort.setManaged(showDetails);
+ });
+ lblProxyHost.setVisible(false);
+ txtProxyHost.setVisible(false);
+ lblProxyPort.setVisible(false);
+ txtProxyPort.setVisible(false);
+ lblProxyHost.setManaged(false);
+ txtProxyHost.setManaged(false);
+ lblProxyPort.setManaged(false);
+ txtProxyPort.setManaged(false);
+ }
+
+ public void setViewModel(SigningOptionsViewModel vm) {
+ this.viewModel = vm;
+ bindToViewModel();
+ }
+
+ private void bindToViewModel() {
+ chkTsaEnabled.selectedProperty().bindBidirectional(viewModel.tsaEnabledProperty());
+ txtTsaUrl.textProperty().bindBidirectional(viewModel.tsaUrlProperty());
+ cmbTsaAuthn.valueProperty().bindBidirectional(viewModel.tsaServerAuthnProperty());
+ txtTsaUser.textProperty().bindBidirectional(viewModel.tsaUserProperty());
+ txtTsaPassword.textProperty().bindBidirectional(viewModel.tsaPasswordProperty());
+ txtTsaCertFileType.textProperty().bindBidirectional(viewModel.tsaCertFileTypeProperty());
+ txtTsaCertFile.textProperty().bindBidirectional(viewModel.tsaCertFileProperty());
+ txtTsaCertFilePassword.textProperty().bindBidirectional(viewModel.tsaCertFilePasswordProperty());
+ txtTsaPolicy.textProperty().bindBidirectional(viewModel.tsaPolicyProperty());
+ txtTsaHashAlg.textProperty().bindBidirectional(viewModel.tsaHashAlgProperty());
+
+ chkOcspEnabled.selectedProperty().bindBidirectional(viewModel.ocspEnabledProperty());
+ txtOcspServerUrl.textProperty().bindBidirectional(viewModel.ocspServerUrlProperty());
+ chkCrlEnabled.selectedProperty().bindBidirectional(viewModel.crlEnabledProperty());
+
+ cmbProxyType.valueProperty().bindBidirectional(viewModel.proxyTypeProperty());
+ txtProxyHost.textProperty().bindBidirectional(viewModel.proxyHostProperty());
+
+ // Proxy port: String <-> int
+ viewModel.proxyPortProperty().addListener((obs, o, n) ->
+ txtProxyPort.setText(String.valueOf(n.intValue())));
+ txtProxyPort.setOnAction(e -> {
+ try {
+ viewModel.proxyPortProperty().set(Integer.parseInt(txtProxyPort.getText()));
+ } catch (NumberFormatException ignored) {
+ }
+ });
+
+ // Update visibility from initial loaded values
+ tsaDetailsPane.setVisible(viewModel.tsaEnabledProperty().get());
+ boolean ocspOn = viewModel.ocspEnabledProperty().get();
+ lblOcspServerUrl.setVisible(ocspOn);
+ txtOcspServerUrl.setVisible(ocspOn);
+ lblOcspServerUrl.setManaged(ocspOn);
+ txtOcspServerUrl.setManaged(ocspOn);
+ Proxy.Type pt = viewModel.proxyTypeProperty().get();
+ boolean proxyOn = pt != null && pt != Proxy.Type.DIRECT;
+ lblProxyHost.setVisible(proxyOn);
+ txtProxyHost.setVisible(proxyOn);
+ lblProxyPort.setVisible(proxyOn);
+ txtProxyPort.setVisible(proxyOn);
+ lblProxyHost.setManaged(proxyOn);
+ txtProxyHost.setManaged(proxyOn);
+ lblProxyPort.setManaged(proxyOn);
+ txtProxyPort.setManaged(proxyOn);
+ }
+
+ @FXML
+ private void onBrowseTsaCertFile() {
+ FileChooser fc = new FileChooser();
+ fc.setTitle(RES.get("jfx.gui.dialog.selectTsaCertFile"));
+ File file = fc.showOpenDialog(txtTsaCertFile.getScene().getWindow());
+ if (file != null) txtTsaCertFile.setText(file.getAbsolutePath());
+ }
+}
diff --git a/jsignpdf/src/main/java/net/sf/jsignpdf/fx/viewmodel/DocumentViewModel.java b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/viewmodel/DocumentViewModel.java
new file mode 100644
index 00000000..e5388df6
--- /dev/null
+++ b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/viewmodel/DocumentViewModel.java
@@ -0,0 +1,100 @@
+package net.sf.jsignpdf.fx.viewmodel;
+
+import java.io.File;
+
+import javafx.beans.property.BooleanProperty;
+import javafx.beans.property.DoubleProperty;
+import javafx.beans.property.IntegerProperty;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.ReadOnlyBooleanProperty;
+import javafx.beans.property.ReadOnlyBooleanWrapper;
+import javafx.beans.property.SimpleBooleanProperty;
+import javafx.beans.property.SimpleDoubleProperty;
+import javafx.beans.property.SimpleIntegerProperty;
+import javafx.beans.property.SimpleObjectProperty;
+import javafx.beans.property.SimpleStringProperty;
+import javafx.beans.property.StringProperty;
+import javafx.scene.image.Image;
+
+/**
+ * ViewModel holding the state of the currently loaded PDF document.
+ */
+public class DocumentViewModel {
+
+ private final ObjectProperty documentFile = new SimpleObjectProperty<>();
+ private final IntegerProperty pageCount = new SimpleIntegerProperty(0);
+ private final IntegerProperty currentPage = new SimpleIntegerProperty(1);
+ private final DoubleProperty zoomLevel = new SimpleDoubleProperty(1.0);
+ private final ObjectProperty currentPageImage = new SimpleObjectProperty<>();
+ private final ReadOnlyBooleanWrapper documentLoaded = new ReadOnlyBooleanWrapper(false);
+ private final StringProperty statusText = new SimpleStringProperty("");
+
+ public DocumentViewModel() {
+ documentFile.addListener((obs, oldVal, newVal) ->
+ documentLoaded.set(newVal != null));
+ }
+
+ // --- Document file ---
+ public ObjectProperty documentFileProperty() { return documentFile; }
+ public File getDocumentFile() { return documentFile.get(); }
+ public void setDocumentFile(File file) { documentFile.set(file); }
+
+ // --- Page count ---
+ public IntegerProperty pageCountProperty() { return pageCount; }
+ public int getPageCount() { return pageCount.get(); }
+ public void setPageCount(int count) { pageCount.set(count); }
+
+ // --- Current page (1-based) ---
+ public IntegerProperty currentPageProperty() { return currentPage; }
+ public int getCurrentPage() { return currentPage.get(); }
+ public void setCurrentPage(int page) {
+ if (page >= 1 && page <= getPageCount()) {
+ currentPage.set(page);
+ }
+ }
+
+ // --- Zoom level (1.0 = 100%) ---
+ public DoubleProperty zoomLevelProperty() { return zoomLevel; }
+ public double getZoomLevel() { return zoomLevel.get(); }
+ public void setZoomLevel(double zoom) {
+ zoomLevel.set(Math.max(0.25, Math.min(4.0, zoom)));
+ }
+
+ // --- Current page image ---
+ public ObjectProperty currentPageImageProperty() { return currentPageImage; }
+ public Image getCurrentPageImage() { return currentPageImage.get(); }
+ public void setCurrentPageImage(Image image) { currentPageImage.set(image); }
+
+ // --- Document loaded (read-only) ---
+ public ReadOnlyBooleanProperty documentLoadedProperty() { return documentLoaded.getReadOnlyProperty(); }
+ public boolean isDocumentLoaded() { return documentLoaded.get(); }
+
+ // --- Status text ---
+ public StringProperty statusTextProperty() { return statusText; }
+ public String getStatusText() { return statusText.get(); }
+ public void setStatusText(String text) { statusText.set(text); }
+
+ // --- Navigation helpers ---
+ public boolean canGoNext() { return getCurrentPage() < getPageCount(); }
+ public boolean canGoPrev() { return getCurrentPage() > 1; }
+
+ public void nextPage() {
+ if (canGoNext()) setCurrentPage(getCurrentPage() + 1);
+ }
+
+ public void prevPage() {
+ if (canGoPrev()) setCurrentPage(getCurrentPage() - 1);
+ }
+
+ public void zoomIn() { setZoomLevel(getZoomLevel() + 0.25); }
+ public void zoomOut() { setZoomLevel(getZoomLevel() - 0.25); }
+
+ public void reset() {
+ documentFile.set(null);
+ pageCount.set(0);
+ currentPage.set(1);
+ zoomLevel.set(1.0);
+ currentPageImage.set(null);
+ statusText.set("");
+ }
+}
diff --git a/jsignpdf/src/main/java/net/sf/jsignpdf/fx/viewmodel/SignaturePlacementViewModel.java b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/viewmodel/SignaturePlacementViewModel.java
new file mode 100644
index 00000000..5f490030
--- /dev/null
+++ b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/viewmodel/SignaturePlacementViewModel.java
@@ -0,0 +1,121 @@
+package net.sf.jsignpdf.fx.viewmodel;
+
+import javafx.beans.property.BooleanProperty;
+import javafx.beans.property.DoubleProperty;
+import javafx.beans.property.SimpleBooleanProperty;
+import javafx.beans.property.SimpleDoubleProperty;
+
+/**
+ * ViewModel for the signature placement rectangle on the PDF preview.
+ * Coordinates are relative (0.0 to 1.0) to the rendered page image.
+ * Conversion to PDF coordinates (LLX, LLY, URX, URY) is done during signing.
+ */
+public class SignaturePlacementViewModel {
+
+ private final BooleanProperty placementMode = new SimpleBooleanProperty(false);
+ private final BooleanProperty placed = new SimpleBooleanProperty(false);
+
+ // Relative coordinates (0.0 - 1.0) on the image
+ private final DoubleProperty relX = new SimpleDoubleProperty(0);
+ private final DoubleProperty relY = new SimpleDoubleProperty(0);
+ private final DoubleProperty relWidth = new SimpleDoubleProperty(0.15);
+ private final DoubleProperty relHeight = new SimpleDoubleProperty(0.08);
+
+ // --- Placement mode ---
+ public BooleanProperty placementModeProperty() { return placementMode; }
+ public boolean isPlacementMode() { return placementMode.get(); }
+ public void setPlacementMode(boolean mode) { placementMode.set(mode); }
+
+ // --- Placed ---
+ public BooleanProperty placedProperty() { return placed; }
+ public boolean isPlaced() { return placed.get(); }
+ public void setPlaced(boolean p) { placed.set(p); }
+
+ // --- Relative coordinates ---
+ public DoubleProperty relXProperty() { return relX; }
+ public double getRelX() { return relX.get(); }
+ public void setRelX(double v) {
+ double clamped = clamp(v, 0, 1);
+ relX.set(clamped);
+ // Re-clamp width so relX + relWidth never exceeds 1.0
+ double maxW = 1 - clamped;
+ if (relWidth.get() > maxW) {
+ relWidth.set(Math.max(0.02, maxW));
+ }
+ }
+
+ public DoubleProperty relYProperty() { return relY; }
+ public double getRelY() { return relY.get(); }
+ public void setRelY(double v) {
+ double clamped = clamp(v, 0, 1);
+ relY.set(clamped);
+ // Re-clamp height so relY + relHeight never exceeds 1.0
+ double maxH = 1 - clamped;
+ if (relHeight.get() > maxH) {
+ relHeight.set(Math.max(0.02, maxH));
+ }
+ }
+
+ public DoubleProperty relWidthProperty() { return relWidth; }
+ public double getRelWidth() { return relWidth.get(); }
+ public void setRelWidth(double v) { relWidth.set(Math.max(0.02, Math.min(v, 1 - getRelX()))); }
+
+ public DoubleProperty relHeightProperty() { return relHeight; }
+ public double getRelHeight() { return relHeight.get(); }
+ public void setRelHeight(double v) { relHeight.set(Math.max(0.02, Math.min(v, 1 - getRelY()))); }
+
+ /**
+ * Convert relative image coordinates to PDF coordinates.
+ * PDF origin is bottom-left; image origin is top-left.
+ *
+ * @param pageWidth PDF page width in points
+ * @param pageHeight PDF page height in points
+ * @return float[4] = {LLX, LLY, URX, URY}
+ */
+ public float[] toPdfCoordinates(float pageWidth, float pageHeight) {
+ float llx = (float) (getRelX() * pageWidth);
+ float urx = (float) ((getRelX() + getRelWidth()) * pageWidth);
+ // PDF Y is inverted: image top=0 -> PDF top=pageHeight
+ float ury = (float) ((1.0 - getRelY()) * pageHeight);
+ float lly = (float) ((1.0 - getRelY() - getRelHeight()) * pageHeight);
+ return new float[]{llx, lly, urx, ury};
+ }
+
+ /**
+ * Set relative image coordinates from PDF coordinates.
+ * PDF origin is bottom-left; image origin is top-left.
+ *
+ * @param llx lower-left X in PDF points
+ * @param lly lower-left Y in PDF points
+ * @param urx upper-right X in PDF points
+ * @param ury upper-right Y in PDF points
+ * @param pageWidth PDF page width in points
+ * @param pageHeight PDF page height in points
+ */
+ public void fromPdfCoordinates(float llx, float lly, float urx, float ury,
+ float pageWidth, float pageHeight) {
+ double rX = llx / pageWidth;
+ double rW = (urx - llx) / pageWidth;
+ // PDF Y is inverted: image top=0 corresponds to PDF top=pageHeight
+ double rY = 1.0 - ury / pageHeight;
+ double rH = (ury - lly) / pageHeight;
+ setRelX(rX);
+ setRelY(rY);
+ setRelWidth(rW);
+ setRelHeight(rH);
+ setPlaced(true);
+ }
+
+ public void reset() {
+ placementMode.set(false);
+ placed.set(false);
+ relX.set(0);
+ relY.set(0);
+ relWidth.set(0.15);
+ relHeight.set(0.08);
+ }
+
+ private static double clamp(double value, double min, double max) {
+ return Math.max(min, Math.min(max, value));
+ }
+}
diff --git a/jsignpdf/src/main/java/net/sf/jsignpdf/fx/viewmodel/SigningOptionsViewModel.java b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/viewmodel/SigningOptionsViewModel.java
new file mode 100644
index 00000000..30e574ba
--- /dev/null
+++ b/jsignpdf/src/main/java/net/sf/jsignpdf/fx/viewmodel/SigningOptionsViewModel.java
@@ -0,0 +1,313 @@
+package net.sf.jsignpdf.fx.viewmodel;
+
+import javafx.beans.property.BooleanProperty;
+import javafx.beans.property.FloatProperty;
+import javafx.beans.property.IntegerProperty;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleBooleanProperty;
+import javafx.beans.property.SimpleFloatProperty;
+import javafx.beans.property.SimpleIntegerProperty;
+import javafx.beans.property.SimpleObjectProperty;
+import javafx.beans.property.SimpleStringProperty;
+import javafx.beans.property.StringProperty;
+import net.sf.jsignpdf.BasicSignerOptions;
+import net.sf.jsignpdf.Constants;
+import net.sf.jsignpdf.types.CertificationLevel;
+import net.sf.jsignpdf.types.HashAlgorithm;
+import net.sf.jsignpdf.types.PDFEncryption;
+import net.sf.jsignpdf.types.PrintRight;
+import net.sf.jsignpdf.types.RenderMode;
+import net.sf.jsignpdf.types.ServerAuthentication;
+
+import java.net.Proxy;
+
+/**
+ * JavaFX property adapter wrapping BasicSignerOptions.
+ * Syncs bidirectionally via syncToOptions() / syncFromOptions().
+ */
+public class SigningOptionsViewModel {
+
+ // Certificate settings
+ private final StringProperty ksType = new SimpleStringProperty();
+ private final StringProperty ksFile = new SimpleStringProperty();
+ private final StringProperty ksPassword = new SimpleStringProperty();
+ private final StringProperty keyAlias = new SimpleStringProperty();
+ private final IntegerProperty keyIndex = new SimpleIntegerProperty(Constants.DEFVAL_KEY_INDEX);
+ private final StringProperty keyPassword = new SimpleStringProperty();
+ private final BooleanProperty storePasswords = new SimpleBooleanProperty(false);
+
+ // File settings
+ private final StringProperty outFile = new SimpleStringProperty();
+ private final BooleanProperty append = new SimpleBooleanProperty(Constants.DEFVAL_APPEND);
+
+ // Signature metadata
+ private final StringProperty signerName = new SimpleStringProperty();
+ private final StringProperty reason = new SimpleStringProperty();
+ private final StringProperty location = new SimpleStringProperty();
+ private final StringProperty contact = new SimpleStringProperty();
+
+ // Certification & hash
+ private final ObjectProperty certLevel = new SimpleObjectProperty<>();
+ private final ObjectProperty hashAlgorithm = new SimpleObjectProperty<>();
+
+ // Visible signature
+ private final BooleanProperty visible = new SimpleBooleanProperty(false);
+ private final IntegerProperty page = new SimpleIntegerProperty(Constants.DEFVAL_PAGE);
+ private final FloatProperty positionLLX = new SimpleFloatProperty(Constants.DEFVAL_LLX);
+ private final FloatProperty positionLLY = new SimpleFloatProperty(Constants.DEFVAL_LLY);
+ private final FloatProperty positionURX = new SimpleFloatProperty(Constants.DEFVAL_URX);
+ private final FloatProperty positionURY = new SimpleFloatProperty(Constants.DEFVAL_URY);
+ private final FloatProperty bgImgScale = new SimpleFloatProperty(Constants.DEFVAL_BG_SCALE);
+ private final ObjectProperty renderMode = new SimpleObjectProperty<>();
+ private final StringProperty l2Text = new SimpleStringProperty();
+ private final StringProperty l4Text = new SimpleStringProperty();
+ private final FloatProperty l2TextFontSize = new SimpleFloatProperty(Constants.DEFVAL_L2_FONT_SIZE);
+ private final StringProperty imgPath = new SimpleStringProperty();
+ private final StringProperty bgImgPath = new SimpleStringProperty();
+ private final BooleanProperty acro6Layers = new SimpleBooleanProperty(Constants.DEFVAL_ACRO6LAYERS);
+
+ // PDF Encryption
+ private final ObjectProperty pdfEncryption = new SimpleObjectProperty<>();
+ private final StringProperty pdfOwnerPassword = new SimpleStringProperty();
+ private final StringProperty pdfUserPassword = new SimpleStringProperty();
+ private final StringProperty pdfEncryptionCertFile = new SimpleStringProperty();
+
+ // Rights
+ private final ObjectProperty rightPrinting = new SimpleObjectProperty<>();
+ private final BooleanProperty rightCopy = new SimpleBooleanProperty(true);
+ private final BooleanProperty rightAssembly = new SimpleBooleanProperty(true);
+ private final BooleanProperty rightFillIn = new SimpleBooleanProperty(true);
+ private final BooleanProperty rightScreenReaders = new SimpleBooleanProperty(true);
+ private final BooleanProperty rightModifyAnnotations = new SimpleBooleanProperty(true);
+ private final BooleanProperty rightModifyContents = new SimpleBooleanProperty(true);
+
+ // TSA
+ private final BooleanProperty tsaEnabled = new SimpleBooleanProperty(false);
+ private final StringProperty tsaUrl = new SimpleStringProperty();
+ private final ObjectProperty tsaServerAuthn = new SimpleObjectProperty<>();
+ private final StringProperty tsaUser = new SimpleStringProperty();
+ private final StringProperty tsaPassword = new SimpleStringProperty();
+ private final StringProperty tsaCertFileType = new SimpleStringProperty();
+ private final StringProperty tsaCertFile = new SimpleStringProperty();
+ private final StringProperty tsaCertFilePassword = new SimpleStringProperty();
+ private final StringProperty tsaPolicy = new SimpleStringProperty();
+ private final StringProperty tsaHashAlg = new SimpleStringProperty();
+
+ // OCSP/CRL
+ private final BooleanProperty ocspEnabled = new SimpleBooleanProperty(false);
+ private final StringProperty ocspServerUrl = new SimpleStringProperty();
+ private final BooleanProperty crlEnabled = new SimpleBooleanProperty(false);
+
+ // Proxy
+ private final ObjectProperty proxyType = new SimpleObjectProperty<>(Constants.DEFVAL_PROXY_TYPE);
+ private final StringProperty proxyHost = new SimpleStringProperty();
+ private final IntegerProperty proxyPort = new SimpleIntegerProperty(Constants.DEFVAL_PROXY_PORT);
+
+ /**
+ * Sync values from this ViewModel into a BasicSignerOptions instance.
+ */
+ public void syncToOptions(BasicSignerOptions opts) {
+ opts.setKsType(ksType.get());
+ opts.setKsFile(ksFile.get());
+ opts.setKsPasswd(toCharArray(ksPassword.get()));
+ opts.setKeyAlias(keyAlias.get());
+ opts.setKeyIndex(keyIndex.get());
+ opts.setKeyPasswd(toCharArray(keyPassword.get()));
+ opts.setStorePasswords(storePasswords.get());
+ opts.setOutFile(outFile.get());
+ opts.setAppend(append.get());
+ opts.setSignerName(signerName.get());
+ opts.setReason(reason.get());
+ opts.setLocation(location.get());
+ opts.setContact(contact.get());
+ opts.setCertLevel(certLevel.get());
+ opts.setHashAlgorithm(hashAlgorithm.get());
+
+ // Visible signature
+ opts.setVisible(visible.get());
+ opts.setPage(page.get());
+ opts.setPositionLLX(positionLLX.get());
+ opts.setPositionLLY(positionLLY.get());
+ opts.setPositionURX(positionURX.get());
+ opts.setPositionURY(positionURY.get());
+ opts.setBgImgScale(bgImgScale.get());
+ opts.setRenderMode(renderMode.get());
+ opts.setL2Text(l2Text.get());
+ opts.setL4Text(l4Text.get());
+ opts.setL2TextFontSize(l2TextFontSize.get());
+ opts.setImgPath(imgPath.get());
+ opts.setBgImgPath(bgImgPath.get());
+ opts.setAcro6Layers(acro6Layers.get());
+
+ // Encryption
+ opts.setPdfEncryption(pdfEncryption.get());
+ opts.setPdfOwnerPwd(toCharArray(pdfOwnerPassword.get()));
+ opts.setPdfUserPwd(toCharArray(pdfUserPassword.get()));
+ opts.setPdfEncryptionCertFile(pdfEncryptionCertFile.get());
+
+ // Rights
+ opts.setRightPrinting(rightPrinting.get());
+ opts.setRightCopy(rightCopy.get());
+ opts.setRightAssembly(rightAssembly.get());
+ opts.setRightFillIn(rightFillIn.get());
+ opts.setRightScreanReaders(rightScreenReaders.get());
+ opts.setRightModifyAnnotations(rightModifyAnnotations.get());
+ opts.setRightModifyContents(rightModifyContents.get());
+
+ // TSA
+ opts.setTimestamp(tsaEnabled.get());
+ opts.setTsaUrl(tsaUrl.get());
+ opts.setTsaServerAuthn(tsaServerAuthn.get());
+ opts.setTsaUser(tsaUser.get());
+ opts.setTsaPasswd(tsaPassword.get());
+ opts.setTsaCertFileType(tsaCertFileType.get());
+ opts.setTsaCertFile(tsaCertFile.get());
+ opts.setTsaCertFilePwd(tsaCertFilePassword.get());
+ opts.setTsaPolicy(tsaPolicy.get());
+ opts.setTsaHashAlg(tsaHashAlg.get());
+
+ // OCSP/CRL
+ opts.setOcspEnabled(ocspEnabled.get());
+ opts.setOcspServerUrl(ocspServerUrl.get());
+ opts.setCrlEnabled(crlEnabled.get());
+
+ // Proxy
+ opts.setProxyType(proxyType.get());
+ opts.setProxyHost(proxyHost.get());
+ opts.setProxyPort(proxyPort.get());
+ }
+
+ /**
+ * Sync values from a BasicSignerOptions instance into this ViewModel.
+ */
+ public void syncFromOptions(BasicSignerOptions opts) {
+ ksType.set(opts.getKsType());
+ ksFile.set(opts.getKsFile());
+ ksPassword.set(fromCharArray(opts.getKsPasswd()));
+ keyAlias.set(opts.getKeyAlias());
+ keyIndex.set(opts.getKeyIndex());
+ keyPassword.set(fromCharArray(opts.getKeyPasswd()));
+ storePasswords.set(opts.isStorePasswords());
+ outFile.set(opts.getOutFile());
+ append.set(opts.isAppend());
+ signerName.set(opts.getSignerName());
+ reason.set(opts.getReason());
+ location.set(opts.getLocation());
+ contact.set(opts.getContact());
+ certLevel.set(opts.getCertLevelX());
+ hashAlgorithm.set(opts.getHashAlgorithmX());
+
+ visible.set(opts.isVisible());
+ page.set(opts.getPage());
+ positionLLX.set(opts.getPositionLLX());
+ positionLLY.set(opts.getPositionLLY());
+ positionURX.set(opts.getPositionURX());
+ positionURY.set(opts.getPositionURY());
+ bgImgScale.set(opts.getBgImgScale());
+ renderMode.set(opts.getRenderMode());
+ l2Text.set(opts.getL2Text());
+ l4Text.set(opts.getL4Text());
+ l2TextFontSize.set(opts.getL2TextFontSize());
+ imgPath.set(opts.getImgPath());
+ bgImgPath.set(opts.getBgImgPath());
+ acro6Layers.set(opts.isAcro6Layers());
+
+ pdfEncryption.set(opts.getPdfEncryption());
+ pdfOwnerPassword.set(opts.getPdfOwnerPwdStr());
+ pdfUserPassword.set(opts.getPdfUserPwdStr());
+ pdfEncryptionCertFile.set(opts.getPdfEncryptionCertFile());
+
+ rightPrinting.set(opts.getRightPrinting());
+ rightCopy.set(opts.isRightCopy());
+ rightAssembly.set(opts.isRightAssembly());
+ rightFillIn.set(opts.isRightFillIn());
+ rightScreenReaders.set(opts.isRightScreanReaders());
+ rightModifyAnnotations.set(opts.isRightModifyAnnotations());
+ rightModifyContents.set(opts.isRightModifyContents());
+
+ tsaEnabled.set(opts.isTimestamp());
+ tsaUrl.set(opts.getTsaUrl());
+ tsaServerAuthn.set(opts.getTsaServerAuthn());
+ tsaUser.set(opts.getTsaUser());
+ tsaPassword.set(opts.getTsaPasswd());
+ tsaCertFileType.set(opts.getTsaCertFileType());
+ tsaCertFile.set(opts.getTsaCertFile());
+ tsaCertFilePassword.set(opts.getTsaCertFilePwd());
+ tsaPolicy.set(opts.getTsaPolicy());
+ tsaHashAlg.set(opts.getTsaHashAlg());
+
+ ocspEnabled.set(opts.isOcspEnabled());
+ ocspServerUrl.set(opts.getOcspServerUrl());
+ crlEnabled.set(opts.isCrlEnabled());
+
+ proxyType.set(opts.getProxyType());
+ proxyHost.set(opts.getProxyHost());
+ proxyPort.set(opts.getProxyPort());
+ }
+
+ private static char[] toCharArray(String s) {
+ return s != null ? s.toCharArray() : null;
+ }
+
+ private static String fromCharArray(char[] c) {
+ return c != null ? new String(c) : null;
+ }
+
+ // --- Property accessors ---
+ public StringProperty ksTypeProperty() { return ksType; }
+ public StringProperty ksFileProperty() { return ksFile; }
+ public StringProperty ksPasswordProperty() { return ksPassword; }
+ public StringProperty keyAliasProperty() { return keyAlias; }
+ public IntegerProperty keyIndexProperty() { return keyIndex; }
+ public StringProperty keyPasswordProperty() { return keyPassword; }
+ public BooleanProperty storePasswordsProperty() { return storePasswords; }
+ public StringProperty outFileProperty() { return outFile; }
+ public BooleanProperty appendProperty() { return append; }
+ public StringProperty signerNameProperty() { return signerName; }
+ public StringProperty reasonProperty() { return reason; }
+ public StringProperty locationProperty() { return location; }
+ public StringProperty contactProperty() { return contact; }
+ public ObjectProperty certLevelProperty() { return certLevel; }
+ public ObjectProperty hashAlgorithmProperty() { return hashAlgorithm; }
+ public BooleanProperty visibleProperty() { return visible; }
+ public IntegerProperty pageProperty() { return page; }
+ public FloatProperty positionLLXProperty() { return positionLLX; }
+ public FloatProperty positionLLYProperty() { return positionLLY; }
+ public FloatProperty positionURXProperty() { return positionURX; }
+ public FloatProperty positionURYProperty() { return positionURY; }
+ public FloatProperty bgImgScaleProperty() { return bgImgScale; }
+ public ObjectProperty renderModeProperty() { return renderMode; }
+ public StringProperty l2TextProperty() { return l2Text; }
+ public StringProperty l4TextProperty() { return l4Text; }
+ public FloatProperty l2TextFontSizeProperty() { return l2TextFontSize; }
+ public StringProperty imgPathProperty() { return imgPath; }
+ public StringProperty bgImgPathProperty() { return bgImgPath; }
+ public BooleanProperty acro6LayersProperty() { return acro6Layers; }
+ public ObjectProperty pdfEncryptionProperty() { return pdfEncryption; }
+ public StringProperty pdfOwnerPasswordProperty() { return pdfOwnerPassword; }
+ public StringProperty pdfUserPasswordProperty() { return pdfUserPassword; }
+ public StringProperty pdfEncryptionCertFileProperty() { return pdfEncryptionCertFile; }
+ public ObjectProperty rightPrintingProperty() { return rightPrinting; }
+ public BooleanProperty rightCopyProperty() { return rightCopy; }
+ public BooleanProperty rightAssemblyProperty() { return rightAssembly; }
+ public BooleanProperty rightFillInProperty() { return rightFillIn; }
+ public BooleanProperty rightScreenReadersProperty() { return rightScreenReaders; }
+ public BooleanProperty rightModifyAnnotationsProperty() { return rightModifyAnnotations; }
+ public BooleanProperty rightModifyContentsProperty() { return rightModifyContents; }
+ public BooleanProperty tsaEnabledProperty() { return tsaEnabled; }
+ public StringProperty tsaUrlProperty() { return tsaUrl; }
+ public ObjectProperty tsaServerAuthnProperty() { return tsaServerAuthn; }
+ public StringProperty tsaUserProperty() { return tsaUser; }
+ public StringProperty tsaPasswordProperty() { return tsaPassword; }
+ public StringProperty tsaCertFileTypeProperty() { return tsaCertFileType; }
+ public StringProperty tsaCertFileProperty() { return tsaCertFile; }
+ public StringProperty tsaCertFilePasswordProperty() { return tsaCertFilePassword; }
+ public StringProperty tsaPolicyProperty() { return tsaPolicy; }
+ public StringProperty tsaHashAlgProperty() { return tsaHashAlg; }
+ public BooleanProperty ocspEnabledProperty() { return ocspEnabled; }
+ public StringProperty ocspServerUrlProperty() { return ocspServerUrl; }
+ public BooleanProperty crlEnabledProperty() { return crlEnabled; }
+ public ObjectProperty proxyTypeProperty() { return proxyType; }
+ public StringProperty proxyHostProperty() { return proxyHost; }
+ public IntegerProperty proxyPortProperty() { return proxyPort; }
+}
diff --git a/jsignpdf/src/main/java/net/sf/jsignpdf/utils/KeyStoreUtils.java b/jsignpdf/src/main/java/net/sf/jsignpdf/utils/KeyStoreUtils.java
index d1e66f96..e3f1183f 100644
--- a/jsignpdf/src/main/java/net/sf/jsignpdf/utils/KeyStoreUtils.java
+++ b/jsignpdf/src/main/java/net/sf/jsignpdf/utils/KeyStoreUtils.java
@@ -411,6 +411,9 @@ public static PrivateKeyInfo getPkInfo(BasicSignerOptions options)
final KeyStore tmpKs = loadKeyStore(options.getKsType(), options.getKsFile(), options.getKsPasswd());
String tmpAlias = getKeyAliasInternal(options, tmpKs);
+ if (tmpAlias == null) {
+ return null;
+ }
LOGGER.info(RES.get("console.getPrivateKey"));
final PrivateKey tmpPk = (PrivateKey) tmpKs.getKey(tmpAlias, options.getKeyPasswdX());
LOGGER.info(RES.get("console.getCertChain"));
diff --git a/jsignpdf/src/main/resources/net/sf/jsignpdf/fx/styles/jsignpdf.css b/jsignpdf/src/main/resources/net/sf/jsignpdf/fx/styles/jsignpdf.css
new file mode 100644
index 00000000..ad188cd1
--- /dev/null
+++ b/jsignpdf/src/main/resources/net/sf/jsignpdf/fx/styles/jsignpdf.css
@@ -0,0 +1,81 @@
+/* JSignPdf JavaFX Light Theme */
+
+.root {
+ -fx-font-family: "System";
+ -fx-font-size: 13px;
+ -fx-base: #f0f0f0;
+ -fx-background: #ffffff;
+}
+
+/* Toolbar */
+.main-toolbar {
+ -fx-padding: 4 8 4 8;
+ -fx-spacing: 4;
+}
+
+.toolbar-button {
+ -fx-padding: 4 8 4 8;
+}
+
+.sign-button {
+ -fx-font-weight: bold;
+ -fx-text-fill: #2e7d32;
+}
+
+/* Side Panel */
+.side-panel {
+ -fx-background-color: #f5f5f5;
+}
+
+.placeholder-label {
+ -fx-text-fill: #888888;
+ -fx-padding: 16;
+ -fx-wrap-text: true;
+}
+
+/* PDF Area */
+.pdf-scroll-pane {
+ -fx-background: #e0e0e0;
+ -fx-background-color: #e0e0e0;
+}
+
+.pdf-scroll-pane > .viewport {
+ -fx-background-color: #e0e0e0;
+}
+
+.pdf-area {
+ -fx-background-color: #e0e0e0;
+ -fx-alignment: center;
+}
+
+.drop-hint {
+ -fx-font-size: 18px;
+ -fx-text-fill: #999999;
+ -fx-font-style: italic;
+}
+
+/* Status Bar */
+.status-bar {
+ -fx-background-color: #f0f0f0;
+ -fx-border-color: #cccccc transparent transparent transparent;
+ -fx-border-width: 1 0 0 0;
+}
+
+/* Signature overlay */
+.signature-rect {
+ -fx-stroke: #1565c0;
+ -fx-stroke-width: 2;
+ -fx-fill: rgba(21, 101, 192, 0.15);
+ -fx-stroke-dash-array: 6 4;
+}
+
+.signature-handle {
+ -fx-fill: #1565c0;
+ -fx-stroke: #ffffff;
+ -fx-stroke-width: 1;
+}
+
+/* Accordion in side panel */
+.titled-pane > .title {
+ -fx-font-weight: bold;
+}
diff --git a/jsignpdf/src/main/resources/net/sf/jsignpdf/fx/view/CertificateSettings.fxml b/jsignpdf/src/main/resources/net/sf/jsignpdf/fx/view/CertificateSettings.fxml
new file mode 100644
index 00000000..ff22c208
--- /dev/null
+++ b/jsignpdf/src/main/resources/net/sf/jsignpdf/fx/view/CertificateSettings.fxml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jsignpdf/src/main/resources/net/sf/jsignpdf/fx/view/EncryptionSettings.fxml b/jsignpdf/src/main/resources/net/sf/jsignpdf/fx/view/EncryptionSettings.fxml
new file mode 100644
index 00000000..fd58539d
--- /dev/null
+++ b/jsignpdf/src/main/resources/net/sf/jsignpdf/fx/view/EncryptionSettings.fxml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jsignpdf/src/main/resources/net/sf/jsignpdf/fx/view/MainWindow.fxml b/jsignpdf/src/main/resources/net/sf/jsignpdf/fx/view/MainWindow.fxml
new file mode 100644
index 00000000..db224fde
--- /dev/null
+++ b/jsignpdf/src/main/resources/net/sf/jsignpdf/fx/view/MainWindow.fxml
@@ -0,0 +1,163 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jsignpdf/src/main/resources/net/sf/jsignpdf/fx/view/OutputConsole.fxml b/jsignpdf/src/main/resources/net/sf/jsignpdf/fx/view/OutputConsole.fxml
new file mode 100644
index 00000000..e80a797b
--- /dev/null
+++ b/jsignpdf/src/main/resources/net/sf/jsignpdf/fx/view/OutputConsole.fxml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jsignpdf/src/main/resources/net/sf/jsignpdf/fx/view/SignatureSettings.fxml b/jsignpdf/src/main/resources/net/sf/jsignpdf/fx/view/SignatureSettings.fxml
new file mode 100644
index 00000000..b6652ee3
--- /dev/null
+++ b/jsignpdf/src/main/resources/net/sf/jsignpdf/fx/view/SignatureSettings.fxml
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jsignpdf/src/main/resources/net/sf/jsignpdf/fx/view/TsaSettings.fxml b/jsignpdf/src/main/resources/net/sf/jsignpdf/fx/view/TsaSettings.fxml
new file mode 100644
index 00000000..73c93a5f
--- /dev/null
+++ b/jsignpdf/src/main/resources/net/sf/jsignpdf/fx/view/TsaSettings.fxml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages.properties b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages.properties
index cc0a0b70..2ec8c497 100644
--- a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages.properties
+++ b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages.properties
@@ -256,3 +256,103 @@ serverAuthn.certificate=Client certificate
serverAuthn.none=Without authentication
serverAuthn.password=Username / Password
ssl.keymanager.init=Initializing key manager from keystore file {0}.
+#
+# JavaFX GUI
+#
+jfx.gui.menu.file=File
+jfx.gui.menu.file.open=Open PDF...
+jfx.gui.menu.file.close=Close
+jfx.gui.menu.file.sign=Sign
+jfx.gui.menu.file.recentFiles=Recent Files
+jfx.gui.menu.file.recentFiles.empty=No recent files
+jfx.gui.menu.file.exit=Exit
+jfx.gui.menu.view=View
+jfx.gui.menu.view.zoomIn=Zoom In
+jfx.gui.menu.view.zoomOut=Zoom Out
+jfx.gui.menu.view.fitPage=Fit Page
+jfx.gui.menu.view.toggleSidePanel=Toggle Side Panel
+jfx.gui.menu.signing=Signing
+jfx.gui.menu.help=Help
+jfx.gui.menu.help.about=About JSignPdf
+jfx.gui.toolbar.open=Open
+jfx.gui.toolbar.fit=Fit
+jfx.gui.toolbar.sign=Sign
+jfx.gui.panel.certificate=Certificate
+jfx.gui.panel.signatureAppearance=Signature Appearance
+jfx.gui.panel.timestampValidation=Timestamp & Validation
+jfx.gui.panel.encryptionRights=Encryption & Rights
+jfx.gui.dropHint=Drop a PDF file here or use File > Open
+jfx.gui.status.ready=Ready
+jfx.gui.status.signingInProgress=Signing...
+jfx.gui.status.signingOk=Signing completed successfully
+jfx.gui.status.signingFailed=Signing failed
+jfx.gui.status.renderError=Error rendering page
+jfx.gui.status.readError=Error: Cannot read PDF file
+jfx.gui.dialog.signingComplete.title=Signing Complete
+jfx.gui.dialog.signingComplete.text=The PDF has been signed successfully.
+jfx.gui.dialog.signingFailed.title=Signing Failed
+jfx.gui.dialog.signingFailed.text=The signing process failed. Check the output console for details.
+jfx.gui.dialog.signingError.title=Signing Error
+jfx.gui.dialog.noDocument.title=No Document
+jfx.gui.dialog.noDocument.text=Please open a PDF document first.
+jfx.gui.dialog.openPdf.title=Open PDF
+jfx.gui.dialog.about.description=A free application for PDF signing.
+jfx.gui.dialog.selectKeystoreFile=Select Keystore File
+jfx.gui.dialog.selectSignatureImage=Select Signature Image
+jfx.gui.dialog.selectBackgroundImage=Select Background Image
+jfx.gui.dialog.selectOutputPdf=Select Output PDF File
+jfx.gui.dialog.selectEncryptionCert=Select Encryption Certificate
+jfx.gui.dialog.selectTsaCertFile=Select TSA Certificate File
+jfx.gui.status.shiftToReplace=Hold Shift and drag to replace the signature rectangle
+jfx.gui.cert.keystoreType=Keystore type:
+jfx.gui.cert.keystoreFile=Keystore file:
+jfx.gui.cert.keystorePassword=Keystore password:
+jfx.gui.cert.loadKeys=Load Keys
+jfx.gui.cert.keyAlias=Key alias:
+jfx.gui.cert.keyPassword=Key password:
+jfx.gui.cert.storePasswords=Store passwords
+jfx.gui.sig.enableVisible=Enable visible signature
+jfx.gui.sig.renderMode=Render mode:
+jfx.gui.sig.l2Text=Signature text:
+jfx.gui.sig.l4Text=Status text:
+jfx.gui.sig.fontSize=Font size:
+jfx.gui.sig.signatureImage=Signature image:
+jfx.gui.sig.backgroundImage=Background image:
+jfx.gui.sig.acro6Layers=Acrobat 6 layer mode
+jfx.gui.sig.hashAlgorithm=Hash algorithm:
+jfx.gui.sig.certLevel=Certification level:
+jfx.gui.sig.signerName=Signer name:
+jfx.gui.sig.reason=Reason:
+jfx.gui.sig.location=Location:
+jfx.gui.sig.contact=Contact:
+jfx.gui.sig.appendSignature=Append signature
+jfx.gui.sig.outputFile=Output file:
+jfx.gui.enc.pdfEncryption=PDF Encryption:
+jfx.gui.enc.ownerPassword=Owner password:
+jfx.gui.enc.userPassword=User password:
+jfx.gui.enc.encryptionCert=Encryption certificate:
+jfx.gui.enc.printRight=Print right:
+jfx.gui.enc.allowCopy=Allow Copy
+jfx.gui.enc.allowAssembly=Allow Assembly
+jfx.gui.enc.allowFillIn=Allow Fill-in
+jfx.gui.enc.allowScreenReaders=Allow Screen Readers
+jfx.gui.enc.allowModifyAnnotations=Allow Modify Annotations
+jfx.gui.enc.allowModifyContents=Allow Modify Contents
+jfx.gui.tsa.enableTimestamp=Enable Timestamp (TSA)
+jfx.gui.tsa.serverUrl=TSA server URL:
+jfx.gui.tsa.authentication=Authentication:
+jfx.gui.tsa.user=TSA user:
+jfx.gui.tsa.password=TSA password:
+jfx.gui.tsa.certFileType=TSA cert file type:
+jfx.gui.tsa.certFile=TSA certificate file:
+jfx.gui.tsa.certPassword=TSA cert password:
+jfx.gui.tsa.policyOid=TSA policy OID:
+jfx.gui.tsa.hashAlgorithm=TSA hash algorithm:
+jfx.gui.tsa.enableOcsp=Enable OCSP
+jfx.gui.tsa.ocspServerUrl=OCSP server URL:
+jfx.gui.tsa.enableCrl=Enable CRL
+jfx.gui.tsa.proxyType=Proxy type:
+jfx.gui.tsa.proxyHost=Proxy host:
+jfx.gui.tsa.proxyPort=Proxy port:
+jfx.gui.console.title=Output Console
+jfx.gui.console.clear=Clear
diff --git a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_cs.properties b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_cs.properties
index 8a8f8609..8552902d 100644
--- a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_cs.properties
+++ b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_cs.properties
@@ -256,3 +256,103 @@ console.setSignerName=Nastavuji jm\u00E9no podepisuj\u00EDc\u00EDho: {0}
console.updateVersionNotPossibleInAppendModeForGivenHash=Zvolen\u00FD he\u0161ovac\u00ED algoritmus ({0}) vy\u017Eaduje PDF verzi nov\u011Bj\u0161\u00ED ({1}) ne\u017E v p\u016Fvodn\u00EDm dokumentu ({2}). Zm\u011Bna verze nen\u00ED mo\u017En\u00E1 v re\u017Eimu "p\u0159ipojen\u00ED podpisu k existuj\u00EDc\u00EDm". Bu\u010F vypn\u011Bte p\u0159ipojen\u00ED nebo zvolte jinou he\u0161ovac\u00ED funkci. Toto jsou algoritmy s uveden\u00EDm minim\u00E1ln\u00ED PDF verze: {3}
hlp.signerName=jm\u00E9no podepisuj\u00EDc\u00EDho. V\u00FDchoz\u00ED hodnota je "common name" atribut (CN) ve zvolen\u00E9m certifik\u00E1tu.
hlp.gui=(beta) otev\u0159i GUI i kdy\u017E jsou pou\u017Eity parametry na p\u0159\u00EDkazov\u00E9 \u0159\u00E1dce
+#
+# JavaFX GUI
+#
+jfx.gui.menu.file=Soubor
+jfx.gui.menu.file.open=Otev\u0159\u00edt PDF...
+jfx.gui.menu.file.close=Zav\u0159\u00edt
+jfx.gui.menu.file.sign=Podepsat
+jfx.gui.menu.file.recentFiles=Ned\u00e1vn\u00e9 soubory
+jfx.gui.menu.file.recentFiles.empty=\u017d\u00e1dn\u00e9 ned\u00e1vn\u00e9 soubory
+jfx.gui.menu.file.exit=Ukon\u010dit
+jfx.gui.menu.view=Zobrazen\u00ed
+jfx.gui.menu.view.zoomIn=P\u0159ibl\u00ed\u017eit
+jfx.gui.menu.view.zoomOut=Odd\u00e1lit
+jfx.gui.menu.view.fitPage=P\u0159izp\u016fsobit str\u00e1nce
+jfx.gui.menu.view.toggleSidePanel=P\u0159epnout bo\u010dn\u00ed panel
+jfx.gui.menu.signing=Podepisov\u00e1n\u00ed
+jfx.gui.menu.help=N\u00e1pov\u011bda
+jfx.gui.menu.help.about=O aplikaci JSignPdf
+jfx.gui.toolbar.open=Otev\u0159\u00edt
+jfx.gui.toolbar.fit=P\u0159izp\u016fsobit
+jfx.gui.toolbar.sign=Podepsat
+jfx.gui.panel.certificate=Certifik\u00e1t
+jfx.gui.panel.signatureAppearance=Vzhled podpisu
+jfx.gui.panel.timestampValidation=\u010casov\u00e9 raz\u00edtko a validace
+jfx.gui.panel.encryptionRights=\u0160ifrov\u00e1n\u00ed a pr\u00e1va
+jfx.gui.dropHint=P\u0159et\u00e1hn\u011bte PDF soubor sem nebo pou\u017eijte Soubor > Otev\u0159\u00edt
+jfx.gui.status.ready=P\u0159ipraveno
+jfx.gui.status.signingInProgress=Podepisov\u00e1n\u00ed...
+jfx.gui.status.signingOk=Podepisov\u00e1n\u00ed \u00fasp\u011b\u0161n\u011b dokon\u010deno
+jfx.gui.status.signingFailed=Podepisov\u00e1n\u00ed selhalo
+jfx.gui.status.renderError=Chyba p\u0159i vykreslov\u00e1n\u00ed str\u00e1nky
+jfx.gui.status.readError=Chyba: Nelze p\u0159e\u010d\u00edst PDF soubor
+jfx.gui.status.shiftToReplace=Dr\u017ete Shift a ta\u017een\u00edm nahrad\u00edte obd\u00e9ln\u00edk podpisu
+jfx.gui.dialog.signingComplete.title=Podepisov\u00e1n\u00ed dokon\u010deno
+jfx.gui.dialog.signingComplete.text=PDF byl \u00fasp\u011b\u0161n\u011b podeps\u00e1n.
+jfx.gui.dialog.signingFailed.title=Podepisov\u00e1n\u00ed selhalo
+jfx.gui.dialog.signingFailed.text=Podepisov\u00e1n\u00ed selhalo. Zkontrolujte v\u00fdstupn\u00ed konzoli pro podrobnosti.
+jfx.gui.dialog.signingError.title=Chyba podepisov\u00e1n\u00ed
+jfx.gui.dialog.noDocument.title=\u017d\u00e1dn\u00fd dokument
+jfx.gui.dialog.noDocument.text=Nejprve otev\u0159ete PDF dokument.
+jfx.gui.dialog.openPdf.title=Otev\u0159\u00edt PDF
+jfx.gui.dialog.about.description=Voln\u011b dostupn\u00e1 aplikace pro podepisov\u00e1n\u00ed PDF.
+jfx.gui.dialog.selectKeystoreFile=Vybrat soubor \u00falo\u017ei\u0161t\u011b kl\u00ed\u010d\u016f
+jfx.gui.dialog.selectSignatureImage=Vybrat obr\u00e1zek podpisu
+jfx.gui.dialog.selectBackgroundImage=Vybrat obr\u00e1zek pozad\u00ed
+jfx.gui.dialog.selectOutputPdf=Vybrat v\u00fdstupn\u00ed PDF soubor
+jfx.gui.dialog.selectEncryptionCert=Vybrat certifik\u00e1t pro \u0161ifrov\u00e1n\u00ed
+jfx.gui.dialog.selectTsaCertFile=Vybrat soubor certifik\u00e1tu TSA
+jfx.gui.cert.keystoreType=Typ \u00falo\u017ei\u0161t\u011b kl\u00ed\u010d\u016f:
+jfx.gui.cert.keystoreFile=Soubor \u00falo\u017ei\u0161t\u011b kl\u00ed\u010d\u016f:
+jfx.gui.cert.keystorePassword=Heslo \u00falo\u017ei\u0161t\u011b kl\u00ed\u010d\u016f:
+jfx.gui.cert.loadKeys=Na\u010d\u00edst kl\u00ed\u010de
+jfx.gui.cert.keyAlias=Alias kl\u00ed\u010de:
+jfx.gui.cert.keyPassword=Heslo kl\u00ed\u010de:
+jfx.gui.cert.storePasswords=Ukl\u00e1dat hesla
+jfx.gui.sig.enableVisible=Povolit viditeln\u00fd podpis
+jfx.gui.sig.renderMode=Re\u017eim zobrazen\u00ed:
+jfx.gui.sig.l2Text=Text podpisu:
+jfx.gui.sig.l4Text=Text stavu:
+jfx.gui.sig.fontSize=Velikost p\u00edsma:
+jfx.gui.sig.signatureImage=Obr\u00e1zek podpisu:
+jfx.gui.sig.backgroundImage=Obr\u00e1zek pozad\u00ed:
+jfx.gui.sig.acro6Layers=Re\u017eim vrstev Acrobat 6
+jfx.gui.sig.hashAlgorithm=Hashovac\u00ed algoritmus:
+jfx.gui.sig.certLevel=\u00darove\u0148 certifikace:
+jfx.gui.sig.signerName=Jm\u00e9no podepisuj\u00edc\u00edho:
+jfx.gui.sig.reason=D\u016fvod:
+jfx.gui.sig.location=M\u00edsto:
+jfx.gui.sig.contact=Kontakt:
+jfx.gui.sig.appendSignature=P\u0159ipojit podpis
+jfx.gui.sig.outputFile=V\u00fdstupn\u00ed soubor:
+jfx.gui.enc.pdfEncryption=\u0160ifrov\u00e1n\u00ed PDF:
+jfx.gui.enc.ownerPassword=Heslo vlastn\u00edka:
+jfx.gui.enc.userPassword=Heslo u\u017eivatele:
+jfx.gui.enc.encryptionCert=Certifik\u00e1t pro \u0161ifrov\u00e1n\u00ed:
+jfx.gui.enc.printRight=Pr\u00e1vo tisku:
+jfx.gui.enc.allowCopy=Povolit kop\u00edrov\u00e1n\u00ed
+jfx.gui.enc.allowAssembly=Povolit sestaven\u00ed
+jfx.gui.enc.allowFillIn=Povolit vypl\u0148ov\u00e1n\u00ed
+jfx.gui.enc.allowScreenReaders=Povolit \u010dte\u010dky obrazovky
+jfx.gui.enc.allowModifyAnnotations=Povolit \u00fapravy anotac\u00ed
+jfx.gui.enc.allowModifyContents=Povolit \u00fapravy obsahu
+jfx.gui.tsa.enableTimestamp=Povolit \u010dasov\u00e9 raz\u00edtko (TSA)
+jfx.gui.tsa.serverUrl=URL serveru TSA:
+jfx.gui.tsa.authentication=Autentizace:
+jfx.gui.tsa.user=U\u017eivatel TSA:
+jfx.gui.tsa.password=Heslo TSA:
+jfx.gui.tsa.certFileType=Typ souboru certifik\u00e1tu TSA:
+jfx.gui.tsa.certFile=Soubor certifik\u00e1tu TSA:
+jfx.gui.tsa.certPassword=Heslo certifik\u00e1tu TSA:
+jfx.gui.tsa.policyOid=OID politiky TSA:
+jfx.gui.tsa.hashAlgorithm=Hashovac\u00ed algoritmus TSA:
+jfx.gui.tsa.enableOcsp=Povolit OCSP
+jfx.gui.tsa.ocspServerUrl=URL serveru OCSP:
+jfx.gui.tsa.enableCrl=Povolit CRL
+jfx.gui.tsa.proxyType=Typ proxy:
+jfx.gui.tsa.proxyHost=Hostitel proxy:
+jfx.gui.tsa.proxyPort=Port proxy:
+jfx.gui.console.title=V\u00fdstupn\u00ed konzole
+jfx.gui.console.clear=Vymazat
diff --git a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_de.properties b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_de.properties
index 07b10319..6dee914d 100644
--- a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_de.properties
+++ b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_de.properties
@@ -252,3 +252,103 @@ hlp.help=gibt diesen Hilfebildschirm aus
hlp.keyIndex=Schl\u00FCsselreihenfolge (die Sequenz beginnt bei Null), die zum Signieren des Dokuments verwendet werden soll. Wird weder diese Option noch der Schl\u00FCsselname (Alias) verwendet, wird der erste im Repository gefundene Schl\u00FCssel (Index = 0) verwendet. Diese Option hat weniger Priorit\u00E4t als ein Alias.
hlp.header=JSignPdf ist eine Anwendung zum digitalen Signieren von PDF-Dokumenten. Wenn Sie das Programm ohne Kommandozeilenargument starten, wird die grafische Benutzeroberfl\u00E4che (GUI) gestartet, andernfalls k\u00F6nnen Sie JSignPdf im Kommandozeilen-Batch-Modus verwenden.
hlp.proxyHost=Hostname oder IP-Adresse des Proxy-Servers
+#
+# JavaFX GUI
+#
+jfx.gui.menu.file=Datei
+jfx.gui.menu.file.open=PDF \u00f6ffnen...
+jfx.gui.menu.file.close=Schlie\u00dfen
+jfx.gui.menu.file.sign=Signieren
+jfx.gui.menu.file.recentFiles=Zuletzt ge\u00f6ffnet
+jfx.gui.menu.file.recentFiles.empty=Keine zuletzt ge\u00f6ffneten Dateien
+jfx.gui.menu.file.exit=Beenden
+jfx.gui.menu.view=Ansicht
+jfx.gui.menu.view.zoomIn=Vergr\u00f6\u00dfern
+jfx.gui.menu.view.zoomOut=Verkleinern
+jfx.gui.menu.view.fitPage=Seite einpassen
+jfx.gui.menu.view.toggleSidePanel=Seitenleiste umschalten
+jfx.gui.menu.signing=Signierung
+jfx.gui.menu.help=Hilfe
+jfx.gui.menu.help.about=\u00dcber JSignPdf
+jfx.gui.toolbar.open=\u00d6ffnen
+jfx.gui.toolbar.fit=Einpassen
+jfx.gui.toolbar.sign=Signieren
+jfx.gui.panel.certificate=Zertifikat
+jfx.gui.panel.signatureAppearance=Signatur-Darstellung
+jfx.gui.panel.timestampValidation=Zeitstempel & Validierung
+jfx.gui.panel.encryptionRights=Verschl\u00fcsselung & Rechte
+jfx.gui.dropHint=PDF-Datei hierher ziehen oder Datei > \u00d6ffnen verwenden
+jfx.gui.status.ready=Bereit
+jfx.gui.status.signingInProgress=Signierung l\u00e4uft...
+jfx.gui.status.signingOk=Signierung erfolgreich abgeschlossen
+jfx.gui.status.signingFailed=Signierung fehlgeschlagen
+jfx.gui.status.renderError=Fehler beim Rendern der Seite
+jfx.gui.status.readError=Fehler: PDF-Datei kann nicht gelesen werden
+jfx.gui.status.shiftToReplace=Shift gedr\u00fcckt halten und ziehen, um das Unterschriftsrechteck zu ersetzen
+jfx.gui.dialog.signingComplete.title=Signierung abgeschlossen
+jfx.gui.dialog.signingComplete.text=Das PDF wurde erfolgreich signiert.
+jfx.gui.dialog.signingFailed.title=Signierung fehlgeschlagen
+jfx.gui.dialog.signingFailed.text=Die Signierung ist fehlgeschlagen. Pr\u00fcfen Sie die Ausgabekonsole f\u00fcr Details.
+jfx.gui.dialog.signingError.title=Signierungsfehler
+jfx.gui.dialog.noDocument.title=Kein Dokument
+jfx.gui.dialog.noDocument.text=Bitte \u00f6ffnen Sie zuerst ein PDF-Dokument.
+jfx.gui.dialog.openPdf.title=PDF \u00f6ffnen
+jfx.gui.dialog.about.description=Eine freie Anwendung zum Signieren von PDF-Dateien.
+jfx.gui.dialog.selectKeystoreFile=Keystore-Datei ausw\u00e4hlen
+jfx.gui.dialog.selectSignatureImage=Signaturbild ausw\u00e4hlen
+jfx.gui.dialog.selectBackgroundImage=Hintergrundbild ausw\u00e4hlen
+jfx.gui.dialog.selectOutputPdf=Ausgabe-PDF-Datei ausw\u00e4hlen
+jfx.gui.dialog.selectEncryptionCert=Verschl\u00fcsselungszertifikat ausw\u00e4hlen
+jfx.gui.dialog.selectTsaCertFile=TSA-Zertifikatsdatei ausw\u00e4hlen
+jfx.gui.cert.keystoreType=Keystore-Typ:
+jfx.gui.cert.keystoreFile=Keystore-Datei:
+jfx.gui.cert.keystorePassword=Keystore-Passwort:
+jfx.gui.cert.loadKeys=Schl\u00fcssel laden
+jfx.gui.cert.keyAlias=Schl\u00fcssel-Alias:
+jfx.gui.cert.keyPassword=Schl\u00fcssel-Passwort:
+jfx.gui.cert.storePasswords=Passw\u00f6rter speichern
+jfx.gui.sig.enableVisible=Sichtbare Signatur aktivieren
+jfx.gui.sig.renderMode=Darstellungsmodus:
+jfx.gui.sig.l2Text=Signaturtext:
+jfx.gui.sig.l4Text=Statustext:
+jfx.gui.sig.fontSize=Schriftgr\u00f6\u00dfe:
+jfx.gui.sig.signatureImage=Signaturbild:
+jfx.gui.sig.backgroundImage=Hintergrundbild:
+jfx.gui.sig.acro6Layers=Acrobat 6 Ebenenmodus
+jfx.gui.sig.hashAlgorithm=Hash-Algorithmus:
+jfx.gui.sig.certLevel=Zertifizierungsstufe:
+jfx.gui.sig.signerName=Name des Unterzeichners:
+jfx.gui.sig.reason=Grund:
+jfx.gui.sig.location=Ort:
+jfx.gui.sig.contact=Kontakt:
+jfx.gui.sig.appendSignature=Signatur anh\u00e4ngen
+jfx.gui.sig.outputFile=Ausgabedatei:
+jfx.gui.enc.pdfEncryption=PDF-Verschl\u00fcsselung:
+jfx.gui.enc.ownerPassword=Eigent\u00fcmer-Passwort:
+jfx.gui.enc.userPassword=Benutzer-Passwort:
+jfx.gui.enc.encryptionCert=Verschl\u00fcsselungszertifikat:
+jfx.gui.enc.printRight=Druckrecht:
+jfx.gui.enc.allowCopy=Kopieren erlauben
+jfx.gui.enc.allowAssembly=Zusammenstellung erlauben
+jfx.gui.enc.allowFillIn=Ausf\u00fcllen erlauben
+jfx.gui.enc.allowScreenReaders=Bildschirmleseger\u00e4te erlauben
+jfx.gui.enc.allowModifyAnnotations=Anmerkungen \u00e4ndern erlauben
+jfx.gui.enc.allowModifyContents=Inhalt \u00e4ndern erlauben
+jfx.gui.tsa.enableTimestamp=Zeitstempel aktivieren (TSA)
+jfx.gui.tsa.serverUrl=TSA-Server-URL:
+jfx.gui.tsa.authentication=Authentifizierung:
+jfx.gui.tsa.user=TSA-Benutzer:
+jfx.gui.tsa.password=TSA-Passwort:
+jfx.gui.tsa.certFileType=TSA-Zertifikatsdateityp:
+jfx.gui.tsa.certFile=TSA-Zertifikatsdatei:
+jfx.gui.tsa.certPassword=TSA-Zertifikatspasswort:
+jfx.gui.tsa.policyOid=TSA-Richtlinie (OID):
+jfx.gui.tsa.hashAlgorithm=TSA-Hash-Algorithmus:
+jfx.gui.tsa.enableOcsp=OCSP aktivieren
+jfx.gui.tsa.ocspServerUrl=OCSP-Server-URL:
+jfx.gui.tsa.enableCrl=CRL aktivieren
+jfx.gui.tsa.proxyType=Proxy-Typ:
+jfx.gui.tsa.proxyHost=Proxy-Host:
+jfx.gui.tsa.proxyPort=Proxy-Port:
+jfx.gui.console.title=Ausgabekonsole
+jfx.gui.console.clear=L\u00f6schen
diff --git a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_el.properties b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_el.properties
index 18728927..77295a6b 100644
--- a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_el.properties
+++ b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_el.properties
@@ -239,3 +239,103 @@ serverAuthn.certificate=\u03A0\u03B9\u03C3\u03C4\u03BF\u03C0\u03BF\u03B9\u03B7\u
serverAuthn.none=\u03A7\u03C9\u03C1\u03AF\u03C2 \u03B1\u03C5\u03B8\u03B5\u03BD\u03C4\u03B9\u03BA\u03BF\u03C0\u03BF\u03AF\u03B7\u03C3\u03B7
serverAuthn.password=\u038C\u03BD\u03BF\u03BC\u03B1 \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7 / \u039A\u03C9\u03B4\u03B9\u03BA\u03CC\u03C2
ssl.keymanager.init=\u0391\u03C1\u03C7\u03B9\u03BA\u03BF\u03C0\u03BF\u03AF\u03B7\u03C3\u03B7 \u03C4\u03BF\u03C5 \u03B4\u03B9\u03B1\u03C7\u03B5\u03B9\u03C1\u03B9\u03C3\u03C4\u03AE \u03BA\u03BB\u03B5\u03B9\u03B4\u03B9\u03CE\u03BD \u03B1\u03C0\u03CC \u03C4\u03BF \u03B1\u03C1\u03C7\u03B5\u03AF\u03BF \u03C7\u03CE\u03C1\u03BF\u03C5 \u03B1\u03C0\u03BF\u03B8\u03AE\u03BA\u03B5\u03C5\u03C3\u03B7\u03C2 \u03BA\u03BB\u03B5\u03B9\u03B4\u03B9\u03CE\u03BD {0}.
+#
+# JavaFX GUI
+#
+jfx.gui.menu.file=\u0391\u03c1\u03c7\u03b5\u03af\u03bf
+jfx.gui.menu.file.open=\u0386\u03bd\u03bf\u03b9\u03b3\u03bc\u03b1 PDF...
+jfx.gui.menu.file.close=\u039a\u03bb\u03b5\u03af\u03c3\u03b9\u03bc\u03bf
+jfx.gui.menu.file.sign=\u03a5\u03c0\u03bf\u03b3\u03c1\u03b1\u03c6\u03ae
+jfx.gui.menu.file.recentFiles=\u03a0\u03c1\u03cc\u03c3\u03c6\u03b1\u03c4\u03b1 \u03b1\u03c1\u03c7\u03b5\u03af\u03b1
+jfx.gui.menu.file.recentFiles.empty=\u0394\u03b5\u03bd \u03c5\u03c0\u03ac\u03c1\u03c7\u03bf\u03c5\u03bd \u03c0\u03c1\u03cc\u03c3\u03c6\u03b1\u03c4\u03b1 \u03b1\u03c1\u03c7\u03b5\u03af\u03b1
+jfx.gui.menu.file.exit=\u0388\u03be\u03bf\u03b4\u03bf\u03c2
+jfx.gui.menu.view=\u03a0\u03c1\u03bf\u03b2\u03bf\u03bb\u03ae
+jfx.gui.menu.view.zoomIn=\u039c\u03b5\u03b3\u03ad\u03b8\u03c5\u03bd\u03c3\u03b7
+jfx.gui.menu.view.zoomOut=\u03a3\u03bc\u03af\u03ba\u03c1\u03c5\u03bd\u03c3\u03b7
+jfx.gui.menu.view.fitPage=\u03a0\u03c1\u03bf\u03c3\u03b1\u03c1\u03bc\u03bf\u03b3\u03ae \u03c3\u03b5\u03bb\u03af\u03b4\u03b1\u03c2
+jfx.gui.menu.view.toggleSidePanel=\u0395\u03bd\u03b1\u03bb\u03bb\u03b1\u03b3\u03ae \u03c0\u03bb\u03b1\u03ca\u03bd\u03bf\u03cd \u03c0\u03af\u03bd\u03b1\u03ba\u03b1
+jfx.gui.menu.signing=\u03a5\u03c0\u03bf\u03b3\u03c1\u03b1\u03c6\u03ae
+jfx.gui.menu.help=\u0392\u03bf\u03ae\u03b8\u03b5\u03b9\u03b1
+jfx.gui.menu.help.about=\u03a3\u03c7\u03b5\u03c4\u03b9\u03ba\u03ac \u03bc\u03b5 \u03c4\u03bf JSignPdf
+jfx.gui.toolbar.open=\u0386\u03bd\u03bf\u03b9\u03b3\u03bc\u03b1
+jfx.gui.toolbar.fit=\u03a0\u03c1\u03bf\u03c3\u03b1\u03c1\u03bc\u03bf\u03b3\u03ae
+jfx.gui.toolbar.sign=\u03a5\u03c0\u03bf\u03b3\u03c1\u03b1\u03c6\u03ae
+jfx.gui.panel.certificate=\u03a0\u03b9\u03c3\u03c4\u03bf\u03c0\u03bf\u03b9\u03b7\u03c4\u03b9\u03ba\u03cc
+jfx.gui.panel.signatureAppearance=\u0395\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7 \u03c5\u03c0\u03bf\u03b3\u03c1\u03b1\u03c6\u03ae\u03c2
+jfx.gui.panel.timestampValidation=\u03a7\u03c1\u03bf\u03bd\u03bf\u03c3\u03ae\u03bc\u03b1\u03bd\u03c3\u03b7 & \u0395\u03c0\u03b9\u03ba\u03cd\u03c1\u03c9\u03c3\u03b7
+jfx.gui.panel.encryptionRights=\u039a\u03c1\u03c5\u03c0\u03c4\u03bf\u03b3\u03c1\u03ac\u03c6\u03b7\u03c3\u03b7 & \u0394\u03b9\u03ba\u03b1\u03b9\u03ce\u03bc\u03b1\u03c4\u03b1
+jfx.gui.dropHint=\u03a3\u03cd\u03c1\u03b5\u03c4\u03b5 \u03ad\u03bd\u03b1 \u03b1\u03c1\u03c7\u03b5\u03af\u03bf PDF \u03b5\u03b4\u03ce \u03ae \u03c7\u03c1\u03b7\u03c3\u03b9\u03bc\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03c4\u03b5 \u0391\u03c1\u03c7\u03b5\u03af\u03bf > \u0386\u03bd\u03bf\u03b9\u03b3\u03bc\u03b1
+jfx.gui.status.ready=\u0388\u03c4\u03bf\u03b9\u03bc\u03bf
+jfx.gui.status.signingInProgress=\u03a5\u03c0\u03bf\u03b3\u03c1\u03b1\u03c6\u03ae...
+jfx.gui.status.signingOk=\u0397 \u03c5\u03c0\u03bf\u03b3\u03c1\u03b1\u03c6\u03ae \u03bf\u03bb\u03bf\u03ba\u03bb\u03b7\u03c1\u03ce\u03b8\u03b7\u03ba\u03b5 \u03b5\u03c0\u03b9\u03c4\u03c5\u03c7\u03ce\u03c2
+jfx.gui.status.signingFailed=\u0397 \u03c5\u03c0\u03bf\u03b3\u03c1\u03b1\u03c6\u03ae \u03b1\u03c0\u03ad\u03c4\u03c5\u03c7\u03b5
+jfx.gui.status.renderError=\u03a3\u03c6\u03ac\u03bb\u03bc\u03b1 \u03b1\u03c0\u03cc\u03b4\u03bf\u03c3\u03b7\u03c2 \u03c3\u03b5\u03bb\u03af\u03b4\u03b1\u03c2
+jfx.gui.status.readError=\u03a3\u03c6\u03ac\u03bb\u03bc\u03b1: \u0394\u03b5\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03b4\u03c5\u03bd\u03b1\u03c4\u03ae \u03b7 \u03b1\u03bd\u03ac\u03b3\u03bd\u03c9\u03c3\u03b7 \u03c4\u03bf\u03c5 PDF
+jfx.gui.status.shiftToReplace=\u039a\u03c1\u03b1\u03c4\u03ae\u03c3\u03c4\u03b5 \u03c4\u03bf Shift \u03ba\u03b1\u03b9 \u03c3\u03cd\u03c1\u03b5\u03c4\u03b5 \u03b3\u03b9\u03b1 \u03bd\u03b1 \u03b1\u03bd\u03c4\u03b9\u03ba\u03b1\u03c4\u03b1\u03c3\u03c4\u03ae\u03c3\u03b5\u03c4\u03b5 \u03c4\u03bf \u03bf\u03c1\u03b8\u03bf\u03b3\u03ce\u03bd\u03b9\u03bf \u03c5\u03c0\u03bf\u03b3\u03c1\u03b1\u03c6\u03ae\u03c2
+jfx.gui.dialog.signingComplete.title=\u03a5\u03c0\u03bf\u03b3\u03c1\u03b1\u03c6\u03ae \u03bf\u03bb\u03bf\u03ba\u03bb\u03b7\u03c1\u03ce\u03b8\u03b7\u03ba\u03b5
+jfx.gui.dialog.signingComplete.text=\u03a4\u03bf PDF \u03c5\u03c0\u03bf\u03b3\u03c1\u03ac\u03c6\u03b7\u03ba\u03b5 \u03b5\u03c0\u03b9\u03c4\u03c5\u03c7\u03ce\u03c2.
+jfx.gui.dialog.signingFailed.title=\u0391\u03c0\u03bf\u03c4\u03c5\u03c7\u03af\u03b1 \u03c5\u03c0\u03bf\u03b3\u03c1\u03b1\u03c6\u03ae\u03c2
+jfx.gui.dialog.signingFailed.text=\u0397 \u03c5\u03c0\u03bf\u03b3\u03c1\u03b1\u03c6\u03ae \u03b1\u03c0\u03ad\u03c4\u03c5\u03c7\u03b5. \u0395\u03bb\u03ad\u03b3\u03be\u03c4\u03b5 \u03c4\u03b7\u03bd \u03ba\u03bf\u03bd\u03c3\u03cc\u03bb\u03b1 \u03b3\u03b9\u03b1 \u03bb\u03b5\u03c0\u03c4\u03bf\u03bc\u03ad\u03c1\u03b5\u03b9\u03b5\u03c2.
+jfx.gui.dialog.signingError.title=\u03a3\u03c6\u03ac\u03bb\u03bc\u03b1 \u03c5\u03c0\u03bf\u03b3\u03c1\u03b1\u03c6\u03ae\u03c2
+jfx.gui.dialog.noDocument.title=\u039a\u03b1\u03bd\u03ad\u03bd\u03b1 \u03ad\u03b3\u03b3\u03c1\u03b1\u03c6\u03bf
+jfx.gui.dialog.noDocument.text=\u03a0\u03b1\u03c1\u03b1\u03ba\u03b1\u03bb\u03ce \u03b1\u03bd\u03bf\u03af\u03be\u03c4\u03b5 \u03c0\u03c1\u03ce\u03c4\u03b1 \u03ad\u03bd\u03b1 \u03ad\u03b3\u03b3\u03c1\u03b1\u03c6\u03bf PDF.
+jfx.gui.dialog.openPdf.title=\u0386\u03bd\u03bf\u03b9\u03b3\u03bc\u03b1 PDF
+jfx.gui.dialog.about.description=\u0394\u03c9\u03c1\u03b5\u03ac\u03bd \u03b5\u03c6\u03b1\u03c1\u03bc\u03bf\u03b3\u03ae \u03b3\u03b9\u03b1 \u03c5\u03c0\u03bf\u03b3\u03c1\u03b1\u03c6\u03ae PDF.
+jfx.gui.dialog.selectKeystoreFile=\u0395\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \u03b1\u03c1\u03c7\u03b5\u03af\u03bf\u03c5 keystore
+jfx.gui.dialog.selectSignatureImage=\u0395\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \u03b5\u03b9\u03ba\u03cc\u03bd\u03b1\u03c2 \u03c5\u03c0\u03bf\u03b3\u03c1\u03b1\u03c6\u03ae\u03c2
+jfx.gui.dialog.selectBackgroundImage=\u0395\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \u03b5\u03b9\u03ba\u03cc\u03bd\u03b1\u03c2 \u03c6\u03cc\u03bd\u03c4\u03bf\u03c5
+jfx.gui.dialog.selectOutputPdf=\u0395\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \u03b1\u03c1\u03c7\u03b5\u03af\u03bf\u03c5 PDF \u03b5\u03be\u03cc\u03b4\u03bf\u03c5
+jfx.gui.dialog.selectEncryptionCert=\u0395\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \u03c0\u03b9\u03c3\u03c4\u03bf\u03c0\u03bf\u03b9\u03b7\u03c4\u03b9\u03ba\u03bf\u03cd \u03ba\u03c1\u03c5\u03c0\u03c4\u03bf\u03b3\u03c1\u03ac\u03c6\u03b7\u03c3\u03b7\u03c2
+jfx.gui.dialog.selectTsaCertFile=\u0395\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \u03b1\u03c1\u03c7\u03b5\u03af\u03bf\u03c5 \u03c0\u03b9\u03c3\u03c4\u03bf\u03c0\u03bf\u03b9\u03b7\u03c4\u03b9\u03ba\u03bf\u03cd TSA
+jfx.gui.cert.keystoreType=\u03a4\u03cd\u03c0\u03bf\u03c2 keystore:
+jfx.gui.cert.keystoreFile=\u0391\u03c1\u03c7\u03b5\u03af\u03bf keystore:
+jfx.gui.cert.keystorePassword=\u039a\u03c9\u03b4\u03b9\u03ba\u03cc\u03c2 keystore:
+jfx.gui.cert.loadKeys=\u03a6\u03cc\u03c1\u03c4\u03c9\u03c3\u03b7 \u03ba\u03bb\u03b5\u03b9\u03b4\u03b9\u03ce\u03bd
+jfx.gui.cert.keyAlias=\u03a8\u03b5\u03c5\u03b4\u03ce\u03bd\u03c5\u03bc\u03bf \u03ba\u03bb\u03b5\u03b9\u03b4\u03b9\u03bf\u03cd:
+jfx.gui.cert.keyPassword=\u039a\u03c9\u03b4\u03b9\u03ba\u03cc\u03c2 \u03ba\u03bb\u03b5\u03b9\u03b4\u03b9\u03bf\u03cd:
+jfx.gui.cert.storePasswords=\u0391\u03c0\u03bf\u03b8\u03ae\u03ba\u03b5\u03c5\u03c3\u03b7 \u03ba\u03c9\u03b4\u03b9\u03ba\u03ce\u03bd
+jfx.gui.sig.enableVisible=\u0395\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7 \u03bf\u03c1\u03b1\u03c4\u03ae\u03c2 \u03c5\u03c0\u03bf\u03b3\u03c1\u03b1\u03c6\u03ae\u03c2
+jfx.gui.sig.renderMode=\u039b\u03b5\u03b9\u03c4\u03bf\u03c5\u03c1\u03b3\u03af\u03b1 \u03b1\u03c0\u03cc\u03b4\u03bf\u03c3\u03b7\u03c2:
+jfx.gui.sig.l2Text=\u039a\u03b5\u03af\u03bc\u03b5\u03bd\u03bf \u03c5\u03c0\u03bf\u03b3\u03c1\u03b1\u03c6\u03ae\u03c2:
+jfx.gui.sig.l4Text=\u039a\u03b5\u03af\u03bc\u03b5\u03bd\u03bf \u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7\u03c2:
+jfx.gui.sig.fontSize=\u039c\u03ad\u03b3\u03b5\u03b8\u03bf\u03c2 \u03b3\u03c1\u03b1\u03bc\u03bc\u03b1\u03c4\u03bf\u03c3\u03b5\u03b9\u03c1\u03ac\u03c2:
+jfx.gui.sig.signatureImage=\u0395\u03b9\u03ba\u03cc\u03bd\u03b1 \u03c5\u03c0\u03bf\u03b3\u03c1\u03b1\u03c6\u03ae\u03c2:
+jfx.gui.sig.backgroundImage=\u0395\u03b9\u03ba\u03cc\u03bd\u03b1 \u03c6\u03cc\u03bd\u03c4\u03bf\u03c5:
+jfx.gui.sig.acro6Layers=\u039b\u03b5\u03b9\u03c4\u03bf\u03c5\u03c1\u03b3\u03af\u03b1 \u03b5\u03c0\u03b9\u03c0\u03ad\u03b4\u03c9\u03bd Acrobat 6
+jfx.gui.sig.hashAlgorithm=\u0391\u03bb\u03b3\u03cc\u03c1\u03b9\u03b8\u03bc\u03bf\u03c2 hash:
+jfx.gui.sig.certLevel=\u0395\u03c0\u03af\u03c0\u03b5\u03b4\u03bf \u03c0\u03b9\u03c3\u03c4\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7\u03c2:
+jfx.gui.sig.signerName=\u038c\u03bd\u03bf\u03bc\u03b1 \u03c5\u03c0\u03bf\u03b3\u03c1\u03ac\u03c6\u03bf\u03bd\u03c4\u03b1:
+jfx.gui.sig.reason=\u039b\u03cc\u03b3\u03bf\u03c2:
+jfx.gui.sig.location=\u03a4\u03bf\u03c0\u03bf\u03b8\u03b5\u03c3\u03af\u03b1:
+jfx.gui.sig.contact=\u0395\u03c0\u03b9\u03ba\u03bf\u03b9\u03bd\u03c9\u03bd\u03af\u03b1:
+jfx.gui.sig.appendSignature=\u03a0\u03c1\u03bf\u03c3\u03b8\u03ae\u03ba\u03b7 \u03c5\u03c0\u03bf\u03b3\u03c1\u03b1\u03c6\u03ae\u03c2
+jfx.gui.sig.outputFile=\u0391\u03c1\u03c7\u03b5\u03af\u03bf \u03b5\u03be\u03cc\u03b4\u03bf\u03c5:
+jfx.gui.enc.pdfEncryption=\u039a\u03c1\u03c5\u03c0\u03c4\u03bf\u03b3\u03c1\u03ac\u03c6\u03b7\u03c3\u03b7 PDF:
+jfx.gui.enc.ownerPassword=\u039a\u03c9\u03b4\u03b9\u03ba\u03cc\u03c2 \u03b9\u03b4\u03b9\u03bf\u03ba\u03c4\u03ae\u03c4\u03b7:
+jfx.gui.enc.userPassword=\u039a\u03c9\u03b4\u03b9\u03ba\u03cc\u03c2 \u03c7\u03c1\u03ae\u03c3\u03c4\u03b7:
+jfx.gui.enc.encryptionCert=\u03a0\u03b9\u03c3\u03c4\u03bf\u03c0\u03bf\u03b9\u03b7\u03c4\u03b9\u03ba\u03cc \u03ba\u03c1\u03c5\u03c0\u03c4\u03bf\u03b3\u03c1\u03ac\u03c6\u03b7\u03c3\u03b7\u03c2:
+jfx.gui.enc.printRight=\u0394\u03b9\u03ba\u03b1\u03af\u03c9\u03bc\u03b1 \u03b5\u03ba\u03c4\u03cd\u03c0\u03c9\u03c3\u03b7\u03c2:
+jfx.gui.enc.allowCopy=\u0391\u03bd\u03c4\u03b9\u03b3\u03c1\u03b1\u03c6\u03ae
+jfx.gui.enc.allowAssembly=\u03a3\u03c5\u03bd\u03b1\u03c1\u03bc\u03bf\u03bb\u03cc\u03b3\u03b7\u03c3\u03b7
+jfx.gui.enc.allowFillIn=\u03a3\u03c5\u03bc\u03c0\u03bb\u03ae\u03c1\u03c9\u03c3\u03b7
+jfx.gui.enc.allowScreenReaders=\u0391\u03bd\u03b1\u03b3\u03bd\u03ce\u03c3\u03c4\u03b5\u03c2 \u03bf\u03b8\u03cc\u03bd\u03b7\u03c2
+jfx.gui.enc.allowModifyAnnotations=\u03a4\u03c1\u03bf\u03c0\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7 \u03c3\u03c7\u03bf\u03bb\u03af\u03c9\u03bd
+jfx.gui.enc.allowModifyContents=\u03a4\u03c1\u03bf\u03c0\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7 \u03c0\u03b5\u03c1\u03b9\u03b5\u03c7\u03bf\u03bc\u03ad\u03bd\u03bf\u03c5
+jfx.gui.tsa.enableTimestamp=\u0395\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7 \u03c7\u03c1\u03bf\u03bd\u03bf\u03c3\u03ae\u03bc\u03b1\u03bd\u03c3\u03b7\u03c2 (TSA)
+jfx.gui.tsa.serverUrl=URL \u03b4\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ae TSA:
+jfx.gui.tsa.authentication=\u03a0\u03b9\u03c3\u03c4\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7:
+jfx.gui.tsa.user=\u03a7\u03c1\u03ae\u03c3\u03c4\u03b7\u03c2 TSA:
+jfx.gui.tsa.password=\u039a\u03c9\u03b4\u03b9\u03ba\u03cc\u03c2 TSA:
+jfx.gui.tsa.certFileType=\u03a4\u03cd\u03c0\u03bf\u03c2 \u03b1\u03c1\u03c7\u03b5\u03af\u03bf\u03c5 \u03c0\u03b9\u03c3\u03c4\u03bf\u03c0\u03bf\u03b9\u03b7\u03c4\u03b9\u03ba\u03bf\u03cd TSA:
+jfx.gui.tsa.certFile=\u0391\u03c1\u03c7\u03b5\u03af\u03bf \u03c0\u03b9\u03c3\u03c4\u03bf\u03c0\u03bf\u03b9\u03b7\u03c4\u03b9\u03ba\u03bf\u03cd TSA:
+jfx.gui.tsa.certPassword=\u039a\u03c9\u03b4\u03b9\u03ba\u03cc\u03c2 \u03c0\u03b9\u03c3\u03c4\u03bf\u03c0\u03bf\u03b9\u03b7\u03c4\u03b9\u03ba\u03bf\u03cd TSA:
+jfx.gui.tsa.policyOid=OID \u03c0\u03bf\u03bb\u03b9\u03c4\u03b9\u03ba\u03ae\u03c2 TSA:
+jfx.gui.tsa.hashAlgorithm=\u0391\u03bb\u03b3\u03cc\u03c1\u03b9\u03b8\u03bc\u03bf\u03c2 hash TSA:
+jfx.gui.tsa.enableOcsp=\u0395\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7 OCSP
+jfx.gui.tsa.ocspServerUrl=URL \u03b4\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ae OCSP:
+jfx.gui.tsa.enableCrl=\u0395\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7 CRL
+jfx.gui.tsa.proxyType=\u03a4\u03cd\u03c0\u03bf\u03c2 proxy:
+jfx.gui.tsa.proxyHost=\u0394\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ae\u03c2 proxy:
+jfx.gui.tsa.proxyPort=\u0398\u03cd\u03c1\u03b1 proxy:
+jfx.gui.console.title=\u039a\u03bf\u03bd\u03c3\u03cc\u03bb\u03b1 \u03b5\u03be\u03cc\u03b4\u03bf\u03c5
+jfx.gui.console.clear=\u039a\u03b1\u03b8\u03b1\u03c1\u03b9\u03c3\u03bc\u03cc\u03c2
diff --git a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_es.properties b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_es.properties
index bbb4f7d6..50dd2859 100644
--- a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_es.properties
+++ b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_es.properties
@@ -256,3 +256,103 @@ hlp.tsaCertFileType=tipo de almac\u00E9n de claves para la autenticaci\u00F3n TS
hlp.gui=(beta) mostrar la interfaz (GUI) incluso cuando se utilizan otros argumentos en la l\u00EDnea de comandos
#console.updateVersionNotPossibleInAppendMode=Choosen configuration requires PDF version update, but it's not possible in the "append" signature mode.
console.updateVersionNotPossibleInAppendModeForGivenHash=El algoritmo de hash elegido ({0}) necesita una versi\u00F3n de PDF m\u00E1s reciente ({1}) que la original ({2}). La actualizaci\u00F3n de versi\u00F3n del PDF es imposible en modo de firma "adjuntar". Desactiva el modo "adjuntar" o elije otro algoritmo hash. Estos son los requisitos del algoritmo: {3}
+#
+# JavaFX GUI
+#
+jfx.gui.menu.file=Archivo
+jfx.gui.menu.file.open=Abrir PDF...
+jfx.gui.menu.file.close=Cerrar
+jfx.gui.menu.file.sign=Firmar
+jfx.gui.menu.file.recentFiles=Archivos recientes
+jfx.gui.menu.file.recentFiles.empty=No hay archivos recientes
+jfx.gui.menu.file.exit=Salir
+jfx.gui.menu.view=Ver
+jfx.gui.menu.view.zoomIn=Acercar
+jfx.gui.menu.view.zoomOut=Alejar
+jfx.gui.menu.view.fitPage=Ajustar a p\u00e1gina
+jfx.gui.menu.view.toggleSidePanel=Alternar panel lateral
+jfx.gui.menu.signing=Firma
+jfx.gui.menu.help=Ayuda
+jfx.gui.menu.help.about=Acerca de JSignPdf
+jfx.gui.toolbar.open=Abrir
+jfx.gui.toolbar.fit=Ajustar
+jfx.gui.toolbar.sign=Firmar
+jfx.gui.panel.certificate=Certificado
+jfx.gui.panel.signatureAppearance=Apariencia de la firma
+jfx.gui.panel.timestampValidation=Sello de tiempo y validaci\u00f3n
+jfx.gui.panel.encryptionRights=Cifrado y derechos
+jfx.gui.dropHint=Arrastre un archivo PDF aqu\u00ed o use Archivo > Abrir
+jfx.gui.status.ready=Listo
+jfx.gui.status.signingInProgress=Firmando...
+jfx.gui.status.signingOk=Firma completada con \u00e9xito
+jfx.gui.status.signingFailed=La firma ha fallado
+jfx.gui.status.renderError=Error al renderizar la p\u00e1gina
+jfx.gui.status.readError=Error: No se puede leer el archivo PDF
+jfx.gui.status.shiftToReplace=Mantenga Shift y arrastre para reemplazar el rect\u00e1ngulo de firma
+jfx.gui.dialog.signingComplete.title=Firma completada
+jfx.gui.dialog.signingComplete.text=El PDF ha sido firmado con \u00e9xito.
+jfx.gui.dialog.signingFailed.title=Firma fallida
+jfx.gui.dialog.signingFailed.text=El proceso de firma ha fallado. Consulte la consola de salida para m\u00e1s detalles.
+jfx.gui.dialog.signingError.title=Error de firma
+jfx.gui.dialog.noDocument.title=Sin documento
+jfx.gui.dialog.noDocument.text=Por favor, abra primero un documento PDF.
+jfx.gui.dialog.openPdf.title=Abrir PDF
+jfx.gui.dialog.about.description=Aplicaci\u00f3n gratuita para firmar archivos PDF.
+jfx.gui.dialog.selectKeystoreFile=Seleccionar archivo de almac\u00e9n de claves
+jfx.gui.dialog.selectSignatureImage=Seleccionar imagen de firma
+jfx.gui.dialog.selectBackgroundImage=Seleccionar imagen de fondo
+jfx.gui.dialog.selectOutputPdf=Seleccionar archivo PDF de salida
+jfx.gui.dialog.selectEncryptionCert=Seleccionar certificado de cifrado
+jfx.gui.dialog.selectTsaCertFile=Seleccionar archivo de certificado TSA
+jfx.gui.cert.keystoreType=Tipo de almac\u00e9n de claves:
+jfx.gui.cert.keystoreFile=Archivo de almac\u00e9n de claves:
+jfx.gui.cert.keystorePassword=Contrase\u00f1a del almac\u00e9n:
+jfx.gui.cert.loadKeys=Cargar claves
+jfx.gui.cert.keyAlias=Alias de la clave:
+jfx.gui.cert.keyPassword=Contrase\u00f1a de la clave:
+jfx.gui.cert.storePasswords=Guardar contrase\u00f1as
+jfx.gui.sig.enableVisible=Activar firma visible
+jfx.gui.sig.renderMode=Modo de visualizaci\u00f3n:
+jfx.gui.sig.l2Text=Texto de la firma:
+jfx.gui.sig.l4Text=Texto de estado:
+jfx.gui.sig.fontSize=Tama\u00f1o de fuente:
+jfx.gui.sig.signatureImage=Imagen de firma:
+jfx.gui.sig.backgroundImage=Imagen de fondo:
+jfx.gui.sig.acro6Layers=Modo de capas Acrobat 6
+jfx.gui.sig.hashAlgorithm=Algoritmo hash:
+jfx.gui.sig.certLevel=Nivel de certificaci\u00f3n:
+jfx.gui.sig.signerName=Nombre del firmante:
+jfx.gui.sig.reason=Motivo:
+jfx.gui.sig.location=Ubicaci\u00f3n:
+jfx.gui.sig.contact=Contacto:
+jfx.gui.sig.appendSignature=A\u00f1adir firma
+jfx.gui.sig.outputFile=Archivo de salida:
+jfx.gui.enc.pdfEncryption=Cifrado PDF:
+jfx.gui.enc.ownerPassword=Contrase\u00f1a del propietario:
+jfx.gui.enc.userPassword=Contrase\u00f1a del usuario:
+jfx.gui.enc.encryptionCert=Certificado de cifrado:
+jfx.gui.enc.printRight=Derecho de impresi\u00f3n:
+jfx.gui.enc.allowCopy=Permitir copiar
+jfx.gui.enc.allowAssembly=Permitir ensamblaje
+jfx.gui.enc.allowFillIn=Permitir rellenar
+jfx.gui.enc.allowScreenReaders=Permitir lectores de pantalla
+jfx.gui.enc.allowModifyAnnotations=Permitir modificar anotaciones
+jfx.gui.enc.allowModifyContents=Permitir modificar contenido
+jfx.gui.tsa.enableTimestamp=Activar sello de tiempo (TSA)
+jfx.gui.tsa.serverUrl=URL del servidor TSA:
+jfx.gui.tsa.authentication=Autenticaci\u00f3n:
+jfx.gui.tsa.user=Usuario TSA:
+jfx.gui.tsa.password=Contrase\u00f1a TSA:
+jfx.gui.tsa.certFileType=Tipo de archivo de certificado TSA:
+jfx.gui.tsa.certFile=Archivo de certificado TSA:
+jfx.gui.tsa.certPassword=Contrase\u00f1a del certificado TSA:
+jfx.gui.tsa.policyOid=OID de pol\u00edtica TSA:
+jfx.gui.tsa.hashAlgorithm=Algoritmo hash TSA:
+jfx.gui.tsa.enableOcsp=Activar OCSP
+jfx.gui.tsa.ocspServerUrl=URL del servidor OCSP:
+jfx.gui.tsa.enableCrl=Activar CRL
+jfx.gui.tsa.proxyType=Tipo de proxy:
+jfx.gui.tsa.proxyHost=Host del proxy:
+jfx.gui.tsa.proxyPort=Puerto del proxy:
+jfx.gui.console.title=Consola de salida
+jfx.gui.console.clear=Limpiar
diff --git a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_fr.properties b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_fr.properties
index cf1019f7..8df7da22 100644
--- a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_fr.properties
+++ b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_fr.properties
@@ -235,3 +235,103 @@ console.unsupportedEncryptionType=Type de chiffrement non pris en charge.
console.serverNotTrusted=Le certificat du serveur n'est pas fiable. Vous pouvez utiliser l'outil InstallCert pour ajouter le certificat du serveur dans un magasin de certificats de confiance.
console.pdfEncError.wrongCertificateFile=Impossible d'utiliser le chiffrement par certificat du PDF. Le fichier de certificat \u00AB\u00A0{0}\u00A0\u00BB ne peut pas \u00EAtre charg\u00E9 ou il ne contient pas de certificat X509.
console.certificateChainEmpty=Aucune cl\u00E9 priv\u00E9e n'a \u00E9t\u00E9 trouv\u00E9e. V\u00E9rifiez les param\u00E8tres du magasin de certificats (type de magasin, chemin de fichier, mot de passe, alias de cl\u00E9).
+#
+# JavaFX GUI
+#
+jfx.gui.menu.file=Fichier
+jfx.gui.menu.file.open=Ouvrir un PDF...
+jfx.gui.menu.file.close=Fermer
+jfx.gui.menu.file.sign=Signer
+jfx.gui.menu.file.recentFiles=Fichiers r\u00e9cents
+jfx.gui.menu.file.recentFiles.empty=Aucun fichier r\u00e9cent
+jfx.gui.menu.file.exit=Quitter
+jfx.gui.menu.view=Affichage
+jfx.gui.menu.view.zoomIn=Zoom avant
+jfx.gui.menu.view.zoomOut=Zoom arri\u00e8re
+jfx.gui.menu.view.fitPage=Ajuster \u00e0 la page
+jfx.gui.menu.view.toggleSidePanel=Basculer le panneau lat\u00e9ral
+jfx.gui.menu.signing=Signature
+jfx.gui.menu.help=Aide
+jfx.gui.menu.help.about=\u00c0 propos de JSignPdf
+jfx.gui.toolbar.open=Ouvrir
+jfx.gui.toolbar.fit=Ajuster
+jfx.gui.toolbar.sign=Signer
+jfx.gui.panel.certificate=Certificat
+jfx.gui.panel.signatureAppearance=Apparence de la signature
+jfx.gui.panel.timestampValidation=Horodatage et validation
+jfx.gui.panel.encryptionRights=Chiffrement et droits
+jfx.gui.dropHint=D\u00e9posez un fichier PDF ici ou utilisez Fichier > Ouvrir
+jfx.gui.status.ready=Pr\u00eat
+jfx.gui.status.signingInProgress=Signature en cours...
+jfx.gui.status.signingOk=Signature effectu\u00e9e avec succ\u00e8s
+jfx.gui.status.signingFailed=\u00c9chec de la signature
+jfx.gui.status.renderError=Erreur de rendu de la page
+jfx.gui.status.readError=Erreur : impossible de lire le fichier PDF
+jfx.gui.status.shiftToReplace=Maintenez Shift et faites glisser pour remplacer le rectangle de signature
+jfx.gui.dialog.signingComplete.title=Signature termin\u00e9e
+jfx.gui.dialog.signingComplete.text=Le PDF a \u00e9t\u00e9 sign\u00e9 avec succ\u00e8s.
+jfx.gui.dialog.signingFailed.title=\u00c9chec de la signature
+jfx.gui.dialog.signingFailed.text=La signature a \u00e9chou\u00e9. Consultez la console de sortie pour plus de d\u00e9tails.
+jfx.gui.dialog.signingError.title=Erreur de signature
+jfx.gui.dialog.noDocument.title=Aucun document
+jfx.gui.dialog.noDocument.text=Veuillez d'abord ouvrir un document PDF.
+jfx.gui.dialog.openPdf.title=Ouvrir un PDF
+jfx.gui.dialog.about.description=Application gratuite pour la signature de PDF.
+jfx.gui.dialog.selectKeystoreFile=S\u00e9lectionner le fichier keystore
+jfx.gui.dialog.selectSignatureImage=S\u00e9lectionner l'image de signature
+jfx.gui.dialog.selectBackgroundImage=S\u00e9lectionner l'image d'arri\u00e8re-plan
+jfx.gui.dialog.selectOutputPdf=S\u00e9lectionner le fichier PDF de sortie
+jfx.gui.dialog.selectEncryptionCert=S\u00e9lectionner le certificat de chiffrement
+jfx.gui.dialog.selectTsaCertFile=S\u00e9lectionner le fichier de certificat TSA
+jfx.gui.cert.keystoreType=Type de keystore :
+jfx.gui.cert.keystoreFile=Fichier keystore :
+jfx.gui.cert.keystorePassword=Mot de passe du keystore :
+jfx.gui.cert.loadKeys=Charger les cl\u00e9s
+jfx.gui.cert.keyAlias=Alias de la cl\u00e9 :
+jfx.gui.cert.keyPassword=Mot de passe de la cl\u00e9 :
+jfx.gui.cert.storePasswords=Enregistrer les mots de passe
+jfx.gui.sig.enableVisible=Activer la signature visible
+jfx.gui.sig.renderMode=Mode d'affichage :
+jfx.gui.sig.l2Text=Texte de la signature :
+jfx.gui.sig.l4Text=Texte de statut :
+jfx.gui.sig.fontSize=Taille de police :
+jfx.gui.sig.signatureImage=Image de signature :
+jfx.gui.sig.backgroundImage=Image d'arri\u00e8re-plan :
+jfx.gui.sig.acro6Layers=Mode couches Acrobat 6
+jfx.gui.sig.hashAlgorithm=Algorithme de hachage :
+jfx.gui.sig.certLevel=Niveau de certification :
+jfx.gui.sig.signerName=Nom du signataire :
+jfx.gui.sig.reason=Motif :
+jfx.gui.sig.location=Lieu :
+jfx.gui.sig.contact=Contact :
+jfx.gui.sig.appendSignature=Ajouter la signature
+jfx.gui.sig.outputFile=Fichier de sortie :
+jfx.gui.enc.pdfEncryption=Chiffrement PDF :
+jfx.gui.enc.ownerPassword=Mot de passe propri\u00e9taire :
+jfx.gui.enc.userPassword=Mot de passe utilisateur :
+jfx.gui.enc.encryptionCert=Certificat de chiffrement :
+jfx.gui.enc.printRight=Droit d'impression :
+jfx.gui.enc.allowCopy=Autoriser la copie
+jfx.gui.enc.allowAssembly=Autoriser l'assemblage
+jfx.gui.enc.allowFillIn=Autoriser le remplissage
+jfx.gui.enc.allowScreenReaders=Autoriser les lecteurs d'\u00e9cran
+jfx.gui.enc.allowModifyAnnotations=Autoriser la modification des annotations
+jfx.gui.enc.allowModifyContents=Autoriser la modification du contenu
+jfx.gui.tsa.enableTimestamp=Activer l'horodatage (TSA)
+jfx.gui.tsa.serverUrl=URL du serveur TSA :
+jfx.gui.tsa.authentication=Authentification :
+jfx.gui.tsa.user=Utilisateur TSA :
+jfx.gui.tsa.password=Mot de passe TSA :
+jfx.gui.tsa.certFileType=Type de fichier du certificat TSA :
+jfx.gui.tsa.certFile=Fichier de certificat TSA :
+jfx.gui.tsa.certPassword=Mot de passe du certificat TSA :
+jfx.gui.tsa.policyOid=OID de la politique TSA :
+jfx.gui.tsa.hashAlgorithm=Algorithme de hachage TSA :
+jfx.gui.tsa.enableOcsp=Activer OCSP
+jfx.gui.tsa.ocspServerUrl=URL du serveur OCSP :
+jfx.gui.tsa.enableCrl=Activer CRL
+jfx.gui.tsa.proxyType=Type de proxy :
+jfx.gui.tsa.proxyHost=H\u00f4te du proxy :
+jfx.gui.tsa.proxyPort=Port du proxy :
+jfx.gui.console.title=Console de sortie
+jfx.gui.console.clear=Effacer
diff --git a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_hr.properties b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_hr.properties
index 991778ac..72a2d216 100644
--- a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_hr.properties
+++ b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_hr.properties
@@ -256,3 +256,103 @@ extcsp.nosignature=Gre\u0161ka u potpisivanju, potpis nije primljen, nema detalj
extcsp.nosignatureerr=Gre\u0161ka u potpisivanju, spremi\u0161te klju\u010Deva je vratilo gre\u0161ku: {0}
hlp.tsaHashAlg=hash algoritam koji se koristi prilikom dohva\u0107anja vremenskog \u017Eiga servera (TSA); standardna vrijednost je {0}
hlp.tsaPolicy=OID politike servera vremenskog \u017Eiga (TSA) koji treba postaviti za zahtjev vremenskog \u017Eiga.
+#
+# JavaFX GUI
+#
+jfx.gui.menu.file=Datoteka
+jfx.gui.menu.file.open=Otvori PDF...
+jfx.gui.menu.file.close=Zatvori
+jfx.gui.menu.file.sign=Potpi\u0161i
+jfx.gui.menu.file.recentFiles=Nedavne datoteke
+jfx.gui.menu.file.recentFiles.empty=Nema nedavnih datoteka
+jfx.gui.menu.file.exit=Izlaz
+jfx.gui.menu.view=Prikaz
+jfx.gui.menu.view.zoomIn=Pove\u0107aj
+jfx.gui.menu.view.zoomOut=Smanji
+jfx.gui.menu.view.fitPage=Prilagodi stranicu
+jfx.gui.menu.view.toggleSidePanel=Prika\u017Ei/sakrij bo\u010Dnu plo\u010Du
+jfx.gui.menu.signing=Potpisivanje
+jfx.gui.menu.help=Pomo\u0107
+jfx.gui.menu.help.about=O programu JSignPdf
+jfx.gui.toolbar.open=Otvori
+jfx.gui.toolbar.fit=Prilagodi
+jfx.gui.toolbar.sign=Potpi\u0161i
+jfx.gui.panel.certificate=Certifikat
+jfx.gui.panel.signatureAppearance=Izgled potpisa
+jfx.gui.panel.timestampValidation=Vremenski \u017Eig i provjera
+jfx.gui.panel.encryptionRights=\u0160ifriranje i prava
+jfx.gui.dropHint=Povuci PDF datoteku ovdje ili koristi Datoteka > Otvori
+jfx.gui.status.ready=Spreman
+jfx.gui.status.signingInProgress=Potpisivanje...
+jfx.gui.status.signingOk=Potpisivanje uspje\u0161no zavr\u0161eno
+jfx.gui.status.signingFailed=Potpisivanje nije uspjelo
+jfx.gui.status.renderError=Gre\u0161ka pri iscrtavanju stranice
+jfx.gui.status.readError=Gre\u0161ka: PDF datoteka se ne mo\u017Ee pro\u010Ditati
+jfx.gui.status.shiftToReplace=Dr\u017eite Shift i povucite za zamjenu pravokutnika potpisa
+jfx.gui.dialog.signingComplete.title=Potpisivanje zavr\u0161eno
+jfx.gui.dialog.signingComplete.text=PDF je uspje\u0161no potpisan.
+jfx.gui.dialog.signingFailed.title=Potpisivanje nije uspjelo
+jfx.gui.dialog.signingFailed.text=Postupak potpisivanja nije uspio. Provjeri izlaznu konzolu.
+jfx.gui.dialog.signingError.title=Gre\u0161ka pri potpisivanju
+jfx.gui.dialog.noDocument.title=Nema dokumenta
+jfx.gui.dialog.noDocument.text=Najprije otvori PDF dokument.
+jfx.gui.dialog.openPdf.title=Otvori PDF
+jfx.gui.dialog.about.description=Besplatna aplikacija za potpisivanje PDF-a.
+jfx.gui.dialog.selectKeystoreFile=Odaberi datoteku spremi\u0161ta klju\u010Deva
+jfx.gui.dialog.selectSignatureImage=Odaberi sliku potpisa
+jfx.gui.dialog.selectBackgroundImage=Odaberi pozadinsku sliku
+jfx.gui.dialog.selectOutputPdf=Odaberi izlaznu PDF datoteku
+jfx.gui.dialog.selectEncryptionCert=Odaberi certifikat za \u0161ifriranje
+jfx.gui.dialog.selectTsaCertFile=Odaberi datoteku TSA certifikata
+jfx.gui.cert.keystoreType=Vrsta spremi\u0161ta klju\u010Deva:
+jfx.gui.cert.keystoreFile=Datoteka spremi\u0161ta klju\u010Deva:
+jfx.gui.cert.keystorePassword=Lozinka spremi\u0161ta klju\u010Deva:
+jfx.gui.cert.loadKeys=U\u010Ditaj klju\u010Deve
+jfx.gui.cert.keyAlias=Alias klju\u010Da:
+jfx.gui.cert.keyPassword=Lozinka klju\u010Da:
+jfx.gui.cert.storePasswords=Zapamti lozinke
+jfx.gui.sig.enableVisible=Omogu\u0107i vidljiv potpis
+jfx.gui.sig.renderMode=Na\u010Din iscrtavanja:
+jfx.gui.sig.l2Text=Tekst potpisa:
+jfx.gui.sig.l4Text=Tekst stanja:
+jfx.gui.sig.fontSize=Veli\u010Dina fonta:
+jfx.gui.sig.signatureImage=Slika potpisa:
+jfx.gui.sig.backgroundImage=Pozadinska slika:
+jfx.gui.sig.acro6Layers=Acrobat 6 modus slojeva
+jfx.gui.sig.hashAlgorithm=Hash algoritam:
+jfx.gui.sig.certLevel=Razina certifikacije:
+jfx.gui.sig.signerName=Ime potpisnika:
+jfx.gui.sig.reason=Razlog:
+jfx.gui.sig.location=Lokacija:
+jfx.gui.sig.contact=Kontakt:
+jfx.gui.sig.appendSignature=Dodaj potpis
+jfx.gui.sig.outputFile=Izlazna datoteka:
+jfx.gui.enc.pdfEncryption=PDF \u0161ifriranje:
+jfx.gui.enc.ownerPassword=Lozinka vlasnika:
+jfx.gui.enc.userPassword=Lozinka korisnika:
+jfx.gui.enc.encryptionCert=Certifikat za \u0161ifriranje:
+jfx.gui.enc.printRight=Pravo ispisa:
+jfx.gui.enc.allowCopy=Dozvoli kopiranje
+jfx.gui.enc.allowAssembly=Dozvoli sastavljanje
+jfx.gui.enc.allowFillIn=Dozvoli ispunjavanje
+jfx.gui.enc.allowScreenReaders=Dozvoli \u010Dita\u010De ekrana
+jfx.gui.enc.allowModifyAnnotations=Dozvoli mijenjanje bilje\u0161ki
+jfx.gui.enc.allowModifyContents=Dozvoli mijenjanje sadr\u017Eaja
+jfx.gui.tsa.enableTimestamp=Aktiviraj vremenski \u017Eig (TSA)
+jfx.gui.tsa.serverUrl=TSA URL:
+jfx.gui.tsa.authentication=Autentifikacija:
+jfx.gui.tsa.user=TSA korisnik:
+jfx.gui.tsa.password=TSA lozinka:
+jfx.gui.tsa.certFileType=Vrsta TSA datoteke certifikata:
+jfx.gui.tsa.certFile=Datoteka TSA certifikata:
+jfx.gui.tsa.certPassword=Lozinka TSA certifikata:
+jfx.gui.tsa.policyOid=TSA politika OID:
+jfx.gui.tsa.hashAlgorithm=TSA hash algoritam:
+jfx.gui.tsa.enableOcsp=Aktiviraj OCSP
+jfx.gui.tsa.ocspServerUrl=URL OCSP servera:
+jfx.gui.tsa.enableCrl=Aktiviraj CRL
+jfx.gui.tsa.proxyType=Vrsta proxyja:
+jfx.gui.tsa.proxyHost=Proxy ra\u010Dunalo:
+jfx.gui.tsa.proxyPort=Proxy priklju\u010Dak:
+jfx.gui.console.title=Izlazna konzola
+jfx.gui.console.clear=O\u010Disti
diff --git a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_hu.properties b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_hu.properties
index 3b309c36..2fc4fd4e 100644
--- a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_hu.properties
+++ b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_hu.properties
@@ -6,3 +6,103 @@ console.certificateChainEmpty=A priv\u00E1t kulcs nem tal\u00E1lhat\u00F3. Ellen
serverAuthn.password=Felhaszn\u00E1l\u00F3n\u00E9v / Jelsz\u00F3
serverAuthn.certificate=\u00DCgyf\u00E9ltan\u00FAs\u00EDtv\u00E1ny
rights.allowPrinting=Enged\u00E9lyez\u00E9s
+#
+# JavaFX GUI
+#
+jfx.gui.menu.file=F\u00E1jl
+jfx.gui.menu.file.open=PDF megnyit\u00E1sa...
+jfx.gui.menu.file.close=Bez\u00E1r\u00E1s
+jfx.gui.menu.file.sign=Al\u00E1\u00EDr\u00E1s
+jfx.gui.menu.file.recentFiles=Legut\u00f3bbi f\u00e1jlok
+jfx.gui.menu.file.recentFiles.empty=Nincsenek legut\u00f3bbi f\u00e1jlok
+jfx.gui.menu.file.exit=Kil\u00E9p\u00E9s
+jfx.gui.menu.view=N\u00E9zet
+jfx.gui.menu.view.zoomIn=Nagy\u00EDt\u00E1s
+jfx.gui.menu.view.zoomOut=Kicsiny\u00EDt\u00E9s
+jfx.gui.menu.view.fitPage=Oldalhoz igaz\u00EDt\u00E1s
+jfx.gui.menu.view.toggleSidePanel=Oldals\u00E1v be/ki
+jfx.gui.menu.signing=Al\u00E1\u00EDr\u00E1s
+jfx.gui.menu.help=S\u00FAg\u00F3
+jfx.gui.menu.help.about=A JSignPdf-r\u0151l
+jfx.gui.toolbar.open=Megnyit\u00E1s
+jfx.gui.toolbar.fit=Igaz\u00EDt\u00E1s
+jfx.gui.toolbar.sign=Al\u00E1\u00EDr\u00E1s
+jfx.gui.panel.certificate=Tan\u00FAs\u00EDtv\u00E1ny
+jfx.gui.panel.signatureAppearance=Al\u00E1\u00EDr\u00E1s megjelen\u00E9se
+jfx.gui.panel.timestampValidation=Id\u0151b\u00E9lyeg \u00E9s \u00E9rv\u00E9nyes\u00EDt\u00E9s
+jfx.gui.panel.encryptionRights=Titkos\u00EDt\u00E1s \u00E9s jogok
+jfx.gui.dropHint=H\u00FAzzon ide egy PDF f\u00E1jlt, vagy haszn\u00E1lja a F\u00E1jl > Megnyit\u00E1s men\u00FCt
+jfx.gui.status.ready=K\u00E9sz
+jfx.gui.status.signingInProgress=Al\u00E1\u00EDr\u00E1s...
+jfx.gui.status.signingOk=Al\u00E1\u00EDr\u00E1s sikeresen befejez\u0151d\u00F6tt
+jfx.gui.status.signingFailed=Al\u00E1\u00EDr\u00E1s sikertelen
+jfx.gui.status.renderError=Hiba az oldal megjelen\u00EDt\u00E9sekor
+jfx.gui.status.readError=Hiba: A PDF f\u00E1jl nem olvashat\u00F3
+jfx.gui.status.shiftToReplace=Tartsa lenyomva a Shift-et \u00e9s h\u00fazza az al\u00e1\u00edr\u00e1s t\u00e9glalap cser\u00e9j\u00e9hez
+jfx.gui.dialog.signingComplete.title=Al\u00E1\u00EDr\u00E1s befejezve
+jfx.gui.dialog.signingComplete.text=A PDF f\u00E1jl sikeresen al\u00E1\u00EDr\u00E1sra ker\u00FClt.
+jfx.gui.dialog.signingFailed.title=Al\u00E1\u00EDr\u00E1s sikertelen
+jfx.gui.dialog.signingFailed.text=Az al\u00E1\u00EDr\u00E1si folyamat sikertelen. Ellen\u0151rizze a kimeneti konzolt.
+jfx.gui.dialog.signingError.title=Al\u00E1\u00EDr\u00E1si hiba
+jfx.gui.dialog.noDocument.title=Nincs dokumentum
+jfx.gui.dialog.noDocument.text=El\u0151sz\u00F6r nyisson meg egy PDF dokumentumot.
+jfx.gui.dialog.openPdf.title=PDF megnyit\u00E1sa
+jfx.gui.dialog.about.description=Ingyenes alkalmaz\u00E1s PDF al\u00E1\u00EDr\u00E1s\u00E1hoz.
+jfx.gui.dialog.selectKeystoreFile=Kulcstart\u00F3 f\u00E1jl kiv\u00E1laszt\u00E1sa
+jfx.gui.dialog.selectSignatureImage=Al\u00E1\u00EDr\u00E1sk\u00E9p kiv\u00E1laszt\u00E1sa
+jfx.gui.dialog.selectBackgroundImage=H\u00E1tt\u00E9rk\u00E9p kiv\u00E1laszt\u00E1sa
+jfx.gui.dialog.selectOutputPdf=Kimeneti PDF f\u00E1jl kiv\u00E1laszt\u00E1sa
+jfx.gui.dialog.selectEncryptionCert=Titkos\u00EDt\u00E1si tan\u00FAs\u00EDtv\u00E1ny kiv\u00E1laszt\u00E1sa
+jfx.gui.dialog.selectTsaCertFile=TSA tan\u00FAs\u00EDtv\u00E1nyf\u00E1jl kiv\u00E1laszt\u00E1sa
+jfx.gui.cert.keystoreType=Kulcstart\u00F3 t\u00EDpusa:
+jfx.gui.cert.keystoreFile=Kulcstart\u00F3 f\u00E1jl:
+jfx.gui.cert.keystorePassword=Kulcstart\u00F3 jelszava:
+jfx.gui.cert.loadKeys=Kulcsok bet\u00F6lt\u00E9se
+jfx.gui.cert.keyAlias=Kulcs elnevez\u00E9se:
+jfx.gui.cert.keyPassword=Kulcs jelszava:
+jfx.gui.cert.storePasswords=Jelszavak ment\u00E9se
+jfx.gui.sig.enableVisible=L\u00E1that\u00F3 al\u00E1\u00EDr\u00E1s enged\u00E9lyez\u00E9se
+jfx.gui.sig.renderMode=Megjelen\u00EDt\u00E9si m\u00F3d:
+jfx.gui.sig.l2Text=Al\u00E1\u00EDr\u00E1s sz\u00F6vege:
+jfx.gui.sig.l4Text=\u00C1llapot sz\u00F6vege:
+jfx.gui.sig.fontSize=Bet\u0171m\u00E9ret:
+jfx.gui.sig.signatureImage=Al\u00E1\u00EDr\u00E1sk\u00E9p:
+jfx.gui.sig.backgroundImage=H\u00E1tt\u00E9rk\u00E9p:
+jfx.gui.sig.acro6Layers=Acrobat 6 r\u00E9teg m\u00F3d
+jfx.gui.sig.hashAlgorithm=Hash algoritmus:
+jfx.gui.sig.certLevel=Tan\u00FAs\u00EDtv\u00E1nyi szint:
+jfx.gui.sig.signerName=Al\u00E1\u00EDr\u00F3 neve:
+jfx.gui.sig.reason=Ok:
+jfx.gui.sig.location=Helysz\u00EDn:
+jfx.gui.sig.contact=Kapcsolat:
+jfx.gui.sig.appendSignature=Al\u00E1\u00EDr\u00E1s hozz\u00E1f\u0171z\u00E9se
+jfx.gui.sig.outputFile=Kimeneti f\u00E1jl:
+jfx.gui.enc.pdfEncryption=PDF titkos\u00EDt\u00E1s:
+jfx.gui.enc.ownerPassword=Tulajdonos jelszava:
+jfx.gui.enc.userPassword=Felhaszn\u00E1l\u00F3i jelsz\u00F3:
+jfx.gui.enc.encryptionCert=Titkos\u00EDt\u00E1si tan\u00FAs\u00EDtv\u00E1ny:
+jfx.gui.enc.printRight=Nyomtat\u00E1si jog:
+jfx.gui.enc.allowCopy=M\u00E1sol\u00E1s enged\u00E9lyez\u00E9se
+jfx.gui.enc.allowAssembly=\u00D6ssze\u00E1ll\u00EDt\u00E1s enged\u00E9lyez\u00E9se
+jfx.gui.enc.allowFillIn=Kit\u00F6lt\u00E9s enged\u00E9lyez\u00E9se
+jfx.gui.enc.allowScreenReaders=K\u00E9perny\u0151olvas\u00F3k enged\u00E9lyez\u00E9se
+jfx.gui.enc.allowModifyAnnotations=Megjegyz\u00E9sek m\u00F3dos\u00EDt\u00E1sa enged\u00E9lyez\u00E9se
+jfx.gui.enc.allowModifyContents=Tartalom m\u00F3dos\u00EDt\u00E1sa enged\u00E9lyez\u00E9se
+jfx.gui.tsa.enableTimestamp=Id\u0151b\u00E9lyeg enged\u00E9lyez\u00E9se (TSA)
+jfx.gui.tsa.serverUrl=TSA szerver URL:
+jfx.gui.tsa.authentication=Hiteles\u00EDt\u00E9s:
+jfx.gui.tsa.user=TSA felhaszn\u00E1l\u00F3:
+jfx.gui.tsa.password=TSA jelsz\u00F3:
+jfx.gui.tsa.certFileType=TSA tan\u00FAs\u00EDtv\u00E1ny f\u00E1jlt\u00EDpus:
+jfx.gui.tsa.certFile=TSA tan\u00FAs\u00EDtv\u00E1nyf\u00E1jl:
+jfx.gui.tsa.certPassword=TSA tan\u00FAs\u00EDtv\u00E1ny jelszava:
+jfx.gui.tsa.policyOid=TSA szab\u00E1lyzat OID:
+jfx.gui.tsa.hashAlgorithm=TSA hash algoritmus:
+jfx.gui.tsa.enableOcsp=OCSP enged\u00E9lyez\u00E9se
+jfx.gui.tsa.ocspServerUrl=OCSP szerver URL:
+jfx.gui.tsa.enableCrl=CRL enged\u00E9lyez\u00E9se
+jfx.gui.tsa.proxyType=Proxy t\u00EDpusa:
+jfx.gui.tsa.proxyHost=Proxy hoszt:
+jfx.gui.tsa.proxyPort=Proxy port:
+jfx.gui.console.title=Kimeneti konzol
+jfx.gui.console.clear=T\u00F6rl\u00E9s
diff --git a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_hy.properties b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_hy.properties
index b9da5200..810e44db 100644
--- a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_hy.properties
+++ b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_hy.properties
@@ -13,3 +13,103 @@ console.certificateNotForSignature=\u054D\u0565\u0580\u057F\u056B\u0586\u056B\u0
console.configureVisible=\u054F\u0565\u057D\u0561\u0576\u0565\u056C\u056B \u057D\u057F\u0578\u0580\u0561\u0563\u0580\u0578\u0582\u0569\u0575\u0561\u0576 \u056F\u0561\u0580\u0563\u0561\u057E\u0578\u0580\u0578\u0582\u0574
console.createImage=\u054A\u0561\u057F\u056F\u0565\u0580\u056B \u057D\u057F\u0565\u0572\u056E\u0578\u0582\u0574 {0}
console.createPdfReader=\u0544\u0578\u0582\u057F\u0584\u0561\u0575\u056B\u0576 PDF \u0586\u0561\u0575\u056C\u056B \u0562\u0561\u0581\u0578\u0582\u0574\u055D {0}
+#
+# JavaFX GUI
+#
+jfx.gui.menu.file=\u0556\u0561\u0575\u056C
+jfx.gui.menu.file.open=\u0532\u0561\u0581\u0565\u056C PDF...
+jfx.gui.menu.file.close=\u0553\u0561\u056F\u0565\u056C
+jfx.gui.menu.file.sign=\u054D\u057F\u0578\u0580\u0561\u0563\u0580\u0565\u056C
+jfx.gui.menu.file.recentFiles=\u054e\u0565\u0580\u057b\u056b\u0576 \u0586\u0561\u0575\u056c\u0565\u0580
+jfx.gui.menu.file.recentFiles.empty=\u054e\u0565\u0580\u057b\u056b\u0576 \u0586\u0561\u0575\u056c\u0565\u0580 \u0579\u056f\u0561\u0576
+jfx.gui.menu.file.exit=\u0535\u056C\u0584
+jfx.gui.menu.view=\u054F\u0565\u057D\u0584
+jfx.gui.menu.view.zoomIn=\u0544\u0565\u056E\u0561\u0581\u0576\u0565\u056C
+jfx.gui.menu.view.zoomOut=\u0553\u0578\u0584\u0580\u0561\u0581\u0576\u0565\u056C
+jfx.gui.menu.view.fitPage=\u0540\u0561\u0580\u0574\u0561\u0580\u0565\u0581\u0576\u0565\u056C \u0567\u057B\u056B\u0576
+jfx.gui.menu.view.toggleSidePanel=\u0553\u0578\u056D\u0565\u056C \u056F\u0578\u0572\u0574\u0576\u0561\u0575\u056B\u0576 \u057E\u0561\u0570\u0561\u0576\u0561\u056F\u0568
+jfx.gui.menu.signing=\u054D\u057F\u0578\u0580\u0561\u0563\u0580\u0578\u0582\u0574
+jfx.gui.menu.help=\u0555\u0563\u0576\u0578\u0582\u0569\u0575\u0578\u0582\u0576
+jfx.gui.menu.help.about=JSignPdf-\u056B \u0574\u0561\u057D\u056B\u0576
+jfx.gui.toolbar.open=\u0532\u0561\u0581\u0565\u056C
+jfx.gui.toolbar.fit=\u0540\u0561\u0580\u0574\u0561\u0580\u0565\u0581\u0576\u0565\u056C
+jfx.gui.toolbar.sign=\u054D\u057F\u0578\u0580\u0561\u0563\u0580\u0565\u056C
+jfx.gui.panel.certificate=\u054E\u056F\u0561\u0575\u0561\u0563\u056B\u0580
+jfx.gui.panel.signatureAppearance=\u054D\u057F\u0578\u0580\u0561\u0563\u0580\u0578\u0582\u0569\u0575\u0561\u0576 \u0561\u0580\u057F\u0561\u0584\u056B\u0576 \u057F\u0565\u057D\u0584\u0568
+jfx.gui.panel.timestampValidation=\u053A\u0561\u0574\u0561\u0576\u0561\u056F\u0576\u056B\u0584 \u0587 \u057D\u057F\u0578\u0582\u0563\u0578\u0582\u0574
+jfx.gui.panel.encryptionRights=\u0533\u0561\u0572\u057F\u0576\u0561\u0563\u0580\u0578\u0582\u0574 \u0587 \u056B\u0580\u0561\u057E\u0578\u0582\u0576\u0584\u0576\u0565\u0580
+jfx.gui.dropHint=\u0554\u0561\u0577\u0565\u0584 PDF \u0586\u0561\u0575\u056C\u0568 \u0561\u0575\u057D\u057F\u0565\u0572 \u056F\u0561\u0574 \u0585\u0563\u057F\u0561\u0563\u0578\u0580\u056E\u0565\u0584 \u0556\u0561\u0575\u056C > \u0532\u0561\u0581\u0565\u056C
+jfx.gui.status.ready=\u054A\u0561\u057F\u0580\u0561\u057D\u057F
+jfx.gui.status.signingInProgress=\u054D\u057F\u0578\u0580\u0561\u0563\u0580\u0578\u0582\u0574...
+jfx.gui.status.signingOk=\u054D\u057F\u0578\u0580\u0561\u0563\u0580\u0578\u0582\u0574\u0568 \u0570\u0561\u057B\u0578\u0572\u057E\u0565\u0581
+jfx.gui.status.signingFailed=\u054D\u057F\u0578\u0580\u0561\u0563\u0580\u0578\u0582\u0574\u0568 \u0571\u0561\u056D\u0578\u0572\u057E\u0565\u0581
+jfx.gui.status.renderError=\u0537\u057B\u056B \u057A\u0561\u057F\u056F\u0565\u0580\u0574\u0561\u0576 \u057D\u056D\u0561\u056C
+jfx.gui.status.readError=\u054D\u056D\u0561\u056C: \u0540\u0576\u0561\u0580\u0561\u057E\u0578\u0580 \u0579\u0567 \u056F\u0561\u0580\u0564\u0561\u056C PDF \u0586\u0561\u0575\u056C\u0568
+jfx.gui.status.shiftToReplace=\u054d\u0565\u0572\u0574\u0565\u0584 Shift \u0587 \u0584\u0561\u0577\u0565\u0584\u055d \u057d\u057f\u0578\u0580\u0561\u0563\u0580\u0578\u0582\u0569\u0575\u0561\u0576 \u0578\u0582\u0572\u0572\u0561\u0576\u056f\u0575\u0578\u0582\u0576\u0568 \u0583\u0578\u056d\u0561\u0580\u056b\u0576\u0565\u056c\u0578\u0582 \u0570\u0561\u0574\u0561\u0580
+jfx.gui.dialog.signingComplete.title=\u054D\u057F\u0578\u0580\u0561\u0563\u0580\u0578\u0582\u0574\u0568 \u0561\u057E\u0561\u0580\u057F\u057E\u0565\u0581
+jfx.gui.dialog.signingComplete.text=PDF \u0586\u0561\u0575\u056C\u0568 \u0570\u0561\u057B\u0578\u0572\u057E\u0565\u0581 \u057D\u057F\u0578\u0580\u0561\u0563\u0580\u057E\u0565\u056C\u0589
+jfx.gui.dialog.signingFailed.title=\u054D\u057F\u0578\u0580\u0561\u0563\u0580\u0578\u0582\u0574\u0568 \u0571\u0561\u056D\u0578\u0572\u057E\u0565\u0581
+jfx.gui.dialog.signingFailed.text=\u054D\u057F\u0578\u0580\u0561\u0563\u0580\u0574\u0561\u0576 \u0563\u0578\u0580\u056E\u0568\u0576\u0569\u0561\u0581\u0568 \u0571\u0561\u056D\u0578\u0572\u057E\u0565\u0581\u0589 \u054D\u057F\u0578\u0582\u0563\u0565\u0584 \u0565\u056C\u0584\u0561\u0575\u056B\u0576 \u057E\u0561\u0570\u0561\u0576\u0561\u056F\u0568\u0589
+jfx.gui.dialog.signingError.title=\u054D\u057F\u0578\u0580\u0561\u0563\u0580\u0574\u0561\u0576 \u057D\u056D\u0561\u056C
+jfx.gui.dialog.noDocument.title=\u0553\u0561\u057D\u057F\u0561\u0569\u0578\u0582\u0572\u0569 \u0579\u056F\u0561
+jfx.gui.dialog.noDocument.text=\u0546\u0561\u056D \u0562\u0561\u0581\u0565\u0584 PDF \u0583\u0561\u057D\u057F\u0561\u0569\u0578\u0582\u0572\u0569\u0568\u0589
+jfx.gui.dialog.openPdf.title=\u0532\u0561\u0581\u0565\u056C PDF
+jfx.gui.dialog.about.description=PDF \u057D\u057F\u0578\u0580\u0561\u0563\u0580\u0574\u0561\u0576 \u0561\u0576\u057E\u0573\u0561\u0580 \u056E\u0580\u0561\u0563\u056B\u0580\u0589
+jfx.gui.dialog.selectKeystoreFile=\u0538\u0576\u057F\u0580\u0565\u0584 keystore \u0586\u0561\u0575\u056C\u0568
+jfx.gui.dialog.selectSignatureImage=\u0538\u0576\u057F\u0580\u0565\u0584 \u057D\u057F\u0578\u0580\u0561\u0563\u0580\u0578\u0582\u0569\u0575\u0561\u0576 \u057A\u0561\u057F\u056F\u0565\u0580\u0568
+jfx.gui.dialog.selectBackgroundImage=\u0538\u0576\u057F\u0580\u0565\u0584 \u0586\u0578\u0576\u0561\u0575\u056B\u0576 \u057A\u0561\u057F\u056F\u0565\u0580\u0568
+jfx.gui.dialog.selectOutputPdf=\u0538\u0576\u057F\u0580\u0565\u0584 \u0565\u056C\u0584\u0561\u0575\u056B\u0576 PDF \u0586\u0561\u0575\u056C\u0568
+jfx.gui.dialog.selectEncryptionCert=\u0538\u0576\u057F\u0580\u0565\u0584 \u0563\u0561\u0572\u057F\u0576\u0561\u0563\u0580\u0574\u0561\u0576 \u057E\u056F\u0561\u0575\u0561\u0563\u056B\u0580\u0568
+jfx.gui.dialog.selectTsaCertFile=\u0538\u0576\u057F\u0580\u0565\u0584 TSA \u057E\u056F\u0561\u0575\u0561\u0563\u0580\u056B \u0586\u0561\u0575\u056C\u0568
+jfx.gui.cert.keystoreType=Keystore \u057F\u0565\u057D\u0561\u056F\u0568:
+jfx.gui.cert.keystoreFile=Keystore \u0586\u0561\u0575\u056C\u0568:
+jfx.gui.cert.keystorePassword=Keystore \u0563\u0561\u0572\u057F\u0576\u0561\u0562\u0561\u057C\u0568:
+jfx.gui.cert.loadKeys=\u0532\u0565\u057C\u0576\u0565\u056C \u0562\u0561\u0576\u0561\u056C\u056B\u0576\u0565\u0580\u0568
+jfx.gui.cert.keyAlias=\u0532\u0561\u0576\u0561\u056C\u056B\u056B \u0561\u0576\u0578\u0582\u0576\u0568:
+jfx.gui.cert.keyPassword=\u0532\u0561\u0576\u0561\u056C\u056B\u056B \u0563\u0561\u0572\u057F\u0576\u0561\u0562\u0561\u057C\u0568:
+jfx.gui.cert.storePasswords=\u054A\u0561\u0570\u0565\u056C \u0563\u0561\u0572\u057F\u0576\u0561\u0562\u0561\u057C\u0565\u0580\u0568
+jfx.gui.sig.enableVisible=\u0544\u056B\u0561\u0581\u0576\u0565\u056C \u057F\u0565\u057D\u0561\u0576\u0565\u056C\u056B \u057D\u057F\u0578\u0580\u0561\u0563\u0580\u0578\u0582\u0569\u0575\u0578\u0582\u0576\u0568
+jfx.gui.sig.renderMode=\u054A\u0561\u057F\u056F\u0565\u0580\u0574\u0561\u0576 \u057C\u0565\u056A\u056B\u0574\u0568:
+jfx.gui.sig.l2Text=\u054D\u057F\u0578\u0580\u0561\u0563\u0580\u0578\u0582\u0569\u0575\u0561\u0576 \u057F\u0565\u0584\u057D\u057F\u0568:
+jfx.gui.sig.l4Text=\u053F\u0561\u0580\u0563\u0561\u057E\u056B\u0573\u0561\u056F\u056B \u057F\u0565\u0584\u057D\u057F\u0568:
+jfx.gui.sig.fontSize=\u054F\u0561\u057C\u0561\u0579\u0561\u0583\u0568:
+jfx.gui.sig.signatureImage=\u054D\u057F\u0578\u0580\u0561\u0563\u0580\u0578\u0582\u0569\u0575\u0561\u0576 \u057A\u0561\u057F\u056F\u0565\u0580\u0568:
+jfx.gui.sig.backgroundImage=\u0556\u0578\u0576\u0561\u0575\u056B\u0576 \u057A\u0561\u057F\u056F\u0565\u0580\u0568:
+jfx.gui.sig.acro6Layers=Acrobat 6 layer mode
+jfx.gui.sig.hashAlgorithm=Hash \u0561\u056C\u0563\u0578\u0580\u056B\u0569\u0574\u0568:
+jfx.gui.sig.certLevel=\u054E\u056F\u0561\u0575\u0561\u0563\u0580\u0574\u0561\u0576 \u0574\u0561\u056F\u0561\u0580\u0564\u0561\u056F\u0568:
+jfx.gui.sig.signerName=\u054D\u057F\u0578\u0580\u0561\u0563\u0580\u0578\u0572\u056B \u0561\u0576\u0578\u0582\u0576\u0568:
+jfx.gui.sig.reason=\u054A\u0561\u057F\u0573\u0561\u057C\u0568:
+jfx.gui.sig.location=\u054F\u0565\u0572\u0561\u0564\u0580\u0578\u0582\u0569\u0575\u0578\u0582\u0576\u0568:
+jfx.gui.sig.contact=\u053F\u0561\u057A\u0568:
+jfx.gui.sig.appendSignature=\u0531\u057E\u0565\u056C\u0561\u0581\u0576\u0565\u056C \u057D\u057F\u0578\u0580\u0561\u0563\u0580\u0578\u0582\u0569\u0575\u0578\u0582\u0576
+jfx.gui.sig.outputFile=\u0535\u056C\u0584\u0561\u0575\u056B\u0576 \u0586\u0561\u0575\u056C\u0568:
+jfx.gui.enc.pdfEncryption=PDF \u0563\u0561\u0572\u057F\u0576\u0561\u0563\u0580\u0578\u0582\u0574:
+jfx.gui.enc.ownerPassword=\u054D\u0565\u0583\u0561\u056F\u0561\u0576\u0561\u057F\u0565\u0580\u056B \u0563\u0561\u0572\u057F\u0576\u0561\u0562\u0561\u057C\u0568:
+jfx.gui.enc.userPassword=\u0555\u0563\u057F\u0561\u0563\u0578\u0580\u056E\u0578\u0572\u056B \u0563\u0561\u0572\u057F\u0576\u0561\u0562\u0561\u057C\u0568:
+jfx.gui.enc.encryptionCert=\u0533\u0561\u0572\u057F\u0576\u0561\u0563\u0580\u0574\u0561\u0576 \u057E\u056F\u0561\u0575\u0561\u0563\u056B\u0580\u0568:
+jfx.gui.enc.printRight=\u054F\u057A\u0565\u056C\u0578\u0582 \u056B\u0580\u0561\u057E\u0578\u0582\u0576\u0584:
+jfx.gui.enc.allowCopy=\u0539\u0578\u0582\u0575\u056C\u0561\u057F\u0580\u0565\u056C \u057A\u0561\u057F\u0573\u0565\u0576\u0568
+jfx.gui.enc.allowAssembly=\u0539\u0578\u0582\u0575\u056C\u0561\u057F\u0580\u0565\u056C \u0570\u0561\u057E\u0561\u0584\u0578\u0582\u0574\u0568
+jfx.gui.enc.allowFillIn=\u0539\u0578\u0582\u0575\u056C\u0561\u057F\u0580\u0565\u056C \u056C\u0580\u0561\u0581\u0578\u0582\u0574\u0568
+jfx.gui.enc.allowScreenReaders=\u0539\u0578\u0582\u0575\u056C\u0561\u057F\u0580\u0565\u056C \u0567\u056F\u0580\u0561\u0576\u056B \u0568\u0576\u0569\u0565\u0580\u0581\u0578\u0572\u0576\u0565\u0580\u0568
+jfx.gui.enc.allowModifyAnnotations=\u0539\u0578\u0582\u0575\u056C\u0561\u057F\u0580\u0565\u056C \u056E\u0561\u0576\u0578\u0569\u0561\u0563\u0580\u0578\u0582\u0569\u0575\u0578\u0582\u0576\u0576\u0565\u0580\u056B \u0583\u0578\u0583\u0578\u056D\u0578\u0582\u0574\u0568
+jfx.gui.enc.allowModifyContents=\u0539\u0578\u0582\u0575\u056C\u0561\u057F\u0580\u0565\u056C \u0562\u0578\u057E\u0561\u0576\u0564\u0561\u056F\u0578\u0582\u0569\u0575\u0561\u0576 \u0583\u0578\u0583\u0578\u056D\u0578\u0582\u0574\u0568
+jfx.gui.tsa.enableTimestamp=\u0544\u056B\u0561\u0581\u0576\u0565\u056C \u056A\u0561\u0574\u0561\u0576\u0561\u056F\u0576\u056B\u0584\u0568 (TSA)
+jfx.gui.tsa.serverUrl=TSA \u057D\u0565\u0580\u057E\u0565\u0580\u056B URL:
+jfx.gui.tsa.authentication=\u054E\u0561\u057E\u0565\u0580\u0561\u0581\u0578\u0582\u0574:
+jfx.gui.tsa.user=TSA \u0585\u0563\u057F\u0561\u0563\u0578\u0580\u056E\u0578\u0572:
+jfx.gui.tsa.password=TSA \u0563\u0561\u0572\u057F\u0576\u0561\u0562\u0561\u057C:
+jfx.gui.tsa.certFileType=TSA \u057E\u056F\u0561\u0575\u0561\u0563\u0580\u056B \u0586\u0561\u0575\u056C\u056B \u057F\u0565\u057D\u0561\u056F\u0568:
+jfx.gui.tsa.certFile=TSA \u057E\u056F\u0561\u0575\u0561\u0563\u0580\u056B \u0586\u0561\u0575\u056C\u0568:
+jfx.gui.tsa.certPassword=TSA \u057E\u056F\u0561\u0575\u0561\u0563\u0580\u056B \u0563\u0561\u0572\u057F\u0576\u0561\u0562\u0561\u057C\u0568:
+jfx.gui.tsa.policyOid=TSA \u0584\u0561\u0572\u0561\u0584\u0561\u056F\u0561\u0576\u0578\u0582\u0569\u0575\u0561\u0576 OID:
+jfx.gui.tsa.hashAlgorithm=TSA hash \u0561\u056C\u0563\u0578\u0580\u056B\u0569\u0574\u0568:
+jfx.gui.tsa.enableOcsp=\u0544\u056B\u0561\u0581\u0576\u0565\u056C OCSP
+jfx.gui.tsa.ocspServerUrl=OCSP \u057D\u0565\u0580\u057E\u0565\u0580\u056B URL:
+jfx.gui.tsa.enableCrl=\u0544\u056B\u0561\u0581\u0576\u0565\u056C CRL
+jfx.gui.tsa.proxyType=Proxy \u057F\u0565\u057D\u0561\u056F\u0568:
+jfx.gui.tsa.proxyHost=Proxy \u0570\u0578\u057D\u057F\u0568:
+jfx.gui.tsa.proxyPort=Proxy \u057A\u0578\u0580\u057F\u0568:
+jfx.gui.console.title=\u0535\u056C\u0584\u0561\u0575\u056B\u0576 \u057E\u0561\u0570\u0561\u0576\u0561\u056F
+jfx.gui.console.clear=\u0544\u0561\u0584\u0580\u0565\u056C
diff --git a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_it.properties b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_it.properties
index 4873f087..e1938d87 100644
--- a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_it.properties
+++ b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_it.properties
@@ -22,3 +22,103 @@ console.noOCSPURL=URL del server OCSP non trovato nel certificato. Verr\u00E0 ut
console.pdfEncError.wrongCertificateFile=Non \u00E8 possibile utilizzare la crittografia dei certificati del PDF. Il file di certificato "{0}" non pu\u00F2 essere caricato o non contiene un certificato X509.
certificationLevel.formFillAnnot=Inserimento e annotazioni permesse
console.readingCRLs=Lettura delle CRL
+#
+# JavaFX GUI
+#
+jfx.gui.menu.file=File
+jfx.gui.menu.file.open=Apri PDF...
+jfx.gui.menu.file.close=Chiudi
+jfx.gui.menu.file.sign=Firma
+jfx.gui.menu.file.recentFiles=File recenti
+jfx.gui.menu.file.recentFiles.empty=Nessun file recente
+jfx.gui.menu.file.exit=Esci
+jfx.gui.menu.view=Visualizza
+jfx.gui.menu.view.zoomIn=Ingrandisci
+jfx.gui.menu.view.zoomOut=Riduci
+jfx.gui.menu.view.fitPage=Adatta alla pagina
+jfx.gui.menu.view.toggleSidePanel=Mostra/nascondi pannello laterale
+jfx.gui.menu.signing=Firma
+jfx.gui.menu.help=Aiuto
+jfx.gui.menu.help.about=Informazioni su JSignPdf
+jfx.gui.toolbar.open=Apri
+jfx.gui.toolbar.fit=Adatta
+jfx.gui.toolbar.sign=Firma
+jfx.gui.panel.certificate=Certificato
+jfx.gui.panel.signatureAppearance=Aspetto della firma
+jfx.gui.panel.timestampValidation=Marca temporale e validazione
+jfx.gui.panel.encryptionRights=Crittografia e diritti
+jfx.gui.dropHint=Trascina un file PDF qui o usa File > Apri
+jfx.gui.status.ready=Pronto
+jfx.gui.status.signingInProgress=Firma in corso...
+jfx.gui.status.signingOk=Firma completata con successo
+jfx.gui.status.signingFailed=Firma non riuscita
+jfx.gui.status.renderError=Errore nel rendering della pagina
+jfx.gui.status.readError=Errore: impossibile leggere il file PDF
+jfx.gui.status.shiftToReplace=Tieni premuto Shift e trascina per sostituire il rettangolo della firma
+jfx.gui.dialog.signingComplete.title=Firma completata
+jfx.gui.dialog.signingComplete.text=Il PDF \u00e8 stato firmato con successo.
+jfx.gui.dialog.signingFailed.title=Firma non riuscita
+jfx.gui.dialog.signingFailed.text=La firma non \u00e8 riuscita. Controllare la console di output per i dettagli.
+jfx.gui.dialog.signingError.title=Errore di firma
+jfx.gui.dialog.noDocument.title=Nessun documento
+jfx.gui.dialog.noDocument.text=Aprire prima un documento PDF.
+jfx.gui.dialog.openPdf.title=Apri PDF
+jfx.gui.dialog.about.description=Applicazione gratuita per la firma di PDF.
+jfx.gui.dialog.selectKeystoreFile=Seleziona file keystore
+jfx.gui.dialog.selectSignatureImage=Seleziona immagine della firma
+jfx.gui.dialog.selectBackgroundImage=Seleziona immagine di sfondo
+jfx.gui.dialog.selectOutputPdf=Seleziona file PDF di output
+jfx.gui.dialog.selectEncryptionCert=Seleziona certificato di crittografia
+jfx.gui.dialog.selectTsaCertFile=Seleziona file certificato TSA
+jfx.gui.cert.keystoreType=Tipo di keystore:
+jfx.gui.cert.keystoreFile=File keystore:
+jfx.gui.cert.keystorePassword=Password del keystore:
+jfx.gui.cert.loadKeys=Carica chiavi
+jfx.gui.cert.keyAlias=Alias della chiave:
+jfx.gui.cert.keyPassword=Password della chiave:
+jfx.gui.cert.storePasswords=Salva le password
+jfx.gui.sig.enableVisible=Attiva firma visibile
+jfx.gui.sig.renderMode=Modalit\u00e0 di visualizzazione:
+jfx.gui.sig.l2Text=Testo della firma:
+jfx.gui.sig.l4Text=Testo di stato:
+jfx.gui.sig.fontSize=Dimensione del carattere:
+jfx.gui.sig.signatureImage=Immagine della firma:
+jfx.gui.sig.backgroundImage=Immagine di sfondo:
+jfx.gui.sig.acro6Layers=Modalit\u00e0 livelli Acrobat 6
+jfx.gui.sig.hashAlgorithm=Algoritmo di hash:
+jfx.gui.sig.certLevel=Livello di certificazione:
+jfx.gui.sig.signerName=Nome del firmatario:
+jfx.gui.sig.reason=Motivo:
+jfx.gui.sig.location=Luogo:
+jfx.gui.sig.contact=Contatto:
+jfx.gui.sig.appendSignature=Aggiungi firma
+jfx.gui.sig.outputFile=File di output:
+jfx.gui.enc.pdfEncryption=Crittografia PDF:
+jfx.gui.enc.ownerPassword=Password del proprietario:
+jfx.gui.enc.userPassword=Password dell'utente:
+jfx.gui.enc.encryptionCert=Certificato di crittografia:
+jfx.gui.enc.printRight=Diritto di stampa:
+jfx.gui.enc.allowCopy=Consenti copia
+jfx.gui.enc.allowAssembly=Consenti assemblaggio
+jfx.gui.enc.allowFillIn=Consenti compilazione
+jfx.gui.enc.allowScreenReaders=Consenti lettori di schermo
+jfx.gui.enc.allowModifyAnnotations=Consenti modifica annotazioni
+jfx.gui.enc.allowModifyContents=Consenti modifica contenuti
+jfx.gui.tsa.enableTimestamp=Attiva marca temporale (TSA)
+jfx.gui.tsa.serverUrl=URL del server TSA:
+jfx.gui.tsa.authentication=Autenticazione:
+jfx.gui.tsa.user=Utente TSA:
+jfx.gui.tsa.password=Password TSA:
+jfx.gui.tsa.certFileType=Tipo di file del certificato TSA:
+jfx.gui.tsa.certFile=File del certificato TSA:
+jfx.gui.tsa.certPassword=Password del certificato TSA:
+jfx.gui.tsa.policyOid=OID della policy TSA:
+jfx.gui.tsa.hashAlgorithm=Algoritmo di hash TSA:
+jfx.gui.tsa.enableOcsp=Attiva OCSP
+jfx.gui.tsa.ocspServerUrl=URL del server OCSP:
+jfx.gui.tsa.enableCrl=Attiva CRL
+jfx.gui.tsa.proxyType=Tipo di proxy:
+jfx.gui.tsa.proxyHost=Host del proxy:
+jfx.gui.tsa.proxyPort=Porta del proxy:
+jfx.gui.console.title=Console di output
+jfx.gui.console.clear=Cancella
diff --git a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_ja.properties b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_ja.properties
index 7f70f650..dd9d8bee 100644
--- a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_ja.properties
+++ b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_ja.properties
@@ -89,3 +89,103 @@ gui.vs.ury.tooltip = \u30DA\u30FC\u30B8\u4E0A\u306B\u914D\u7F
render.descriptionOnly = \u7F72\u540D\u30C6\u30AD\u30B9\u30C8\u306E\u307F
render.graphicAndDescription = \u30A4\u30E1\u30FC\u30B8\u3068\u7F72\u540D\u30C6\u30AD\u30B9\u30C8
render.signameAndDescription = \u7F72\u540D\u8005\u540D\u3068\u7F72\u540D\u30C6\u30AD\u30B9\u30C8
+#
+# JavaFX GUI
+#
+jfx.gui.menu.file=\u30d5\u30a1\u30a4\u30eb
+jfx.gui.menu.file.open=PDF\u3092\u958b\u304f...
+jfx.gui.menu.file.close=\u9589\u3058\u308b
+jfx.gui.menu.file.sign=\u7f72\u540d
+jfx.gui.menu.file.recentFiles=\u6700\u8fd1\u306e\u30d5\u30a1\u30a4\u30eb
+jfx.gui.menu.file.recentFiles.empty=\u6700\u8fd1\u306e\u30d5\u30a1\u30a4\u30eb\u306f\u3042\u308a\u307e\u305b\u3093
+jfx.gui.menu.file.exit=\u7d42\u4e86
+jfx.gui.menu.view=\u8868\u793a
+jfx.gui.menu.view.zoomIn=\u62e1\u5927
+jfx.gui.menu.view.zoomOut=\u7e2e\u5c0f
+jfx.gui.menu.view.fitPage=\u30da\u30fc\u30b8\u306b\u5408\u308f\u305b\u308b
+jfx.gui.menu.view.toggleSidePanel=\u30b5\u30a4\u30c9\u30d1\u30cd\u30eb\u306e\u5207\u308a\u66ff\u3048
+jfx.gui.menu.signing=\u7f72\u540d
+jfx.gui.menu.help=\u30d8\u30eb\u30d7
+jfx.gui.menu.help.about=JSignPdf\u306b\u3064\u3044\u3066
+jfx.gui.toolbar.open=\u958b\u304f
+jfx.gui.toolbar.fit=\u5408\u308f\u305b\u308b
+jfx.gui.toolbar.sign=\u7f72\u540d
+jfx.gui.panel.certificate=\u8a3c\u660e\u66f8
+jfx.gui.panel.signatureAppearance=\u7f72\u540d\u306e\u5916\u89b3
+jfx.gui.panel.timestampValidation=\u30bf\u30a4\u30e0\u30b9\u30bf\u30f3\u30d7\u3068\u691c\u8a3c
+jfx.gui.panel.encryptionRights=\u6697\u53f7\u5316\u3068\u6a29\u9650
+jfx.gui.dropHint=PDF\u30d5\u30a1\u30a4\u30eb\u3092\u3053\u3053\u306b\u30c9\u30ed\u30c3\u30d7\u3059\u308b\u304b\u3001\u30d5\u30a1\u30a4\u30eb > \u958b\u304f\u3092\u4f7f\u7528
+jfx.gui.status.ready=\u6e96\u5099\u5b8c\u4e86
+jfx.gui.status.signingInProgress=\u7f72\u540d\u4e2d...
+jfx.gui.status.signingOk=\u7f72\u540d\u304c\u6b63\u5e38\u306b\u5b8c\u4e86\u3057\u307e\u3057\u305f
+jfx.gui.status.signingFailed=\u7f72\u540d\u306b\u5931\u6557\u3057\u307e\u3057\u305f
+jfx.gui.status.renderError=\u30da\u30fc\u30b8\u306e\u30ec\u30f3\u30c0\u30ea\u30f3\u30b0\u30a8\u30e9\u30fc
+jfx.gui.status.readError=\u30a8\u30e9\u30fc: PDF\u30d5\u30a1\u30a4\u30eb\u3092\u8aad\u307f\u53d6\u308c\u307e\u305b\u3093
+jfx.gui.status.shiftToReplace=Shift\u3092\u62bc\u3057\u306a\u304c\u3089\u30c9\u30e9\u30c3\u30b0\u3057\u3066\u7f72\u540d\u306e\u77e9\u5f62\u3092\u7f6e\u304d\u63db\u3048
+jfx.gui.dialog.signingComplete.title=\u7f72\u540d\u5b8c\u4e86
+jfx.gui.dialog.signingComplete.text=PDF\u306f\u6b63\u5e38\u306b\u7f72\u540d\u3055\u308c\u307e\u3057\u305f\u3002
+jfx.gui.dialog.signingFailed.title=\u7f72\u540d\u5931\u6557
+jfx.gui.dialog.signingFailed.text=\u7f72\u540d\u30d7\u30ed\u30bb\u30b9\u304c\u5931\u6557\u3057\u307e\u3057\u305f\u3002\u51fa\u529b\u30b3\u30f3\u30bd\u30fc\u30eb\u3092\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044\u3002
+jfx.gui.dialog.signingError.title=\u7f72\u540d\u30a8\u30e9\u30fc
+jfx.gui.dialog.noDocument.title=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u306a\u3057
+jfx.gui.dialog.noDocument.text=\u6700\u521d\u306bPDF\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u3092\u958b\u3044\u3066\u304f\u3060\u3055\u3044\u3002
+jfx.gui.dialog.openPdf.title=PDF\u3092\u958b\u304f
+jfx.gui.dialog.about.description=PDF\u7f72\u540d\u306e\u305f\u3081\u306e\u7121\u6599\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3002
+jfx.gui.dialog.selectKeystoreFile=\u30ad\u30fc\u30b9\u30c8\u30a2\u30d5\u30a1\u30a4\u30eb\u3092\u9078\u629e
+jfx.gui.dialog.selectSignatureImage=\u7f72\u540d\u753b\u50cf\u3092\u9078\u629e
+jfx.gui.dialog.selectBackgroundImage=\u80cc\u666f\u753b\u50cf\u3092\u9078\u629e
+jfx.gui.dialog.selectOutputPdf=\u51fa\u529bPDF\u30d5\u30a1\u30a4\u30eb\u3092\u9078\u629e
+jfx.gui.dialog.selectEncryptionCert=\u6697\u53f7\u5316\u8a3c\u660e\u66f8\u3092\u9078\u629e
+jfx.gui.dialog.selectTsaCertFile=TSA\u8a3c\u660e\u66f8\u30d5\u30a1\u30a4\u30eb\u3092\u9078\u629e
+jfx.gui.cert.keystoreType=\u30ad\u30fc\u30b9\u30c8\u30a2\u30bf\u30a4\u30d7:
+jfx.gui.cert.keystoreFile=\u30ad\u30fc\u30b9\u30c8\u30a2\u30d5\u30a1\u30a4\u30eb:
+jfx.gui.cert.keystorePassword=\u30ad\u30fc\u30b9\u30c8\u30a2\u30d1\u30b9\u30ef\u30fc\u30c9:
+jfx.gui.cert.loadKeys=\u9375\u3092\u8aad\u307f\u8fbc\u3080
+jfx.gui.cert.keyAlias=\u9375\u306e\u30a8\u30a4\u30ea\u30a2\u30b9:
+jfx.gui.cert.keyPassword=\u9375\u306e\u30d1\u30b9\u30ef\u30fc\u30c9:
+jfx.gui.cert.storePasswords=\u30d1\u30b9\u30ef\u30fc\u30c9\u3092\u4fdd\u5b58
+jfx.gui.sig.enableVisible=\u53ef\u8996\u7f72\u540d\u3092\u6709\u52b9\u306b\u3059\u308b
+jfx.gui.sig.renderMode=\u8868\u793a\u30e2\u30fc\u30c9:
+jfx.gui.sig.l2Text=\u7f72\u540d\u30c6\u30ad\u30b9\u30c8:
+jfx.gui.sig.l4Text=\u30b9\u30c6\u30fc\u30bf\u30b9\u30c6\u30ad\u30b9\u30c8:
+jfx.gui.sig.fontSize=\u30d5\u30a9\u30f3\u30c8\u30b5\u30a4\u30ba:
+jfx.gui.sig.signatureImage=\u7f72\u540d\u753b\u50cf:
+jfx.gui.sig.backgroundImage=\u80cc\u666f\u753b\u50cf:
+jfx.gui.sig.acro6Layers=Acrobat 6\u30ec\u30a4\u30e4\u30fc\u30e2\u30fc\u30c9
+jfx.gui.sig.hashAlgorithm=\u30cf\u30c3\u30b7\u30e5\u30a2\u30eb\u30b4\u30ea\u30ba\u30e0:
+jfx.gui.sig.certLevel=\u8a3c\u660e\u30ec\u30d9\u30eb:
+jfx.gui.sig.signerName=\u7f72\u540d\u8005\u540d:
+jfx.gui.sig.reason=\u7406\u7531:
+jfx.gui.sig.location=\u5834\u6240:
+jfx.gui.sig.contact=\u9023\u7d61\u5148:
+jfx.gui.sig.appendSignature=\u7f72\u540d\u3092\u8ffd\u52a0
+jfx.gui.sig.outputFile=\u51fa\u529b\u30d5\u30a1\u30a4\u30eb:
+jfx.gui.enc.pdfEncryption=PDF\u6697\u53f7\u5316:
+jfx.gui.enc.ownerPassword=\u6240\u6709\u8005\u30d1\u30b9\u30ef\u30fc\u30c9:
+jfx.gui.enc.userPassword=\u30e6\u30fc\u30b6\u30fc\u30d1\u30b9\u30ef\u30fc\u30c9:
+jfx.gui.enc.encryptionCert=\u6697\u53f7\u5316\u8a3c\u660e\u66f8:
+jfx.gui.enc.printRight=\u5370\u5237\u6a29\u9650:
+jfx.gui.enc.allowCopy=\u30b3\u30d4\u30fc\u3092\u8a31\u53ef
+jfx.gui.enc.allowAssembly=\u30a2\u30bb\u30f3\u30d6\u30ea\u3092\u8a31\u53ef
+jfx.gui.enc.allowFillIn=\u8a18\u5165\u3092\u8a31\u53ef
+jfx.gui.enc.allowScreenReaders=\u30b9\u30af\u30ea\u30fc\u30f3\u30ea\u30fc\u30c0\u30fc\u3092\u8a31\u53ef
+jfx.gui.enc.allowModifyAnnotations=\u6ce8\u91c8\u306e\u5909\u66f4\u3092\u8a31\u53ef
+jfx.gui.enc.allowModifyContents=\u30b3\u30f3\u30c6\u30f3\u30c4\u306e\u5909\u66f4\u3092\u8a31\u53ef
+jfx.gui.tsa.enableTimestamp=\u30bf\u30a4\u30e0\u30b9\u30bf\u30f3\u30d7\u3092\u6709\u52b9\u306b\u3059\u308b (TSA)
+jfx.gui.tsa.serverUrl=TSA\u30b5\u30fc\u30d0\u30fcURL:
+jfx.gui.tsa.authentication=\u8a8d\u8a3c:
+jfx.gui.tsa.user=TSA\u30e6\u30fc\u30b6\u30fc:
+jfx.gui.tsa.password=TSA\u30d1\u30b9\u30ef\u30fc\u30c9:
+jfx.gui.tsa.certFileType=TSA\u8a3c\u660e\u66f8\u30d5\u30a1\u30a4\u30eb\u30bf\u30a4\u30d7:
+jfx.gui.tsa.certFile=TSA\u8a3c\u660e\u66f8\u30d5\u30a1\u30a4\u30eb:
+jfx.gui.tsa.certPassword=TSA\u8a3c\u660e\u66f8\u30d1\u30b9\u30ef\u30fc\u30c9:
+jfx.gui.tsa.policyOid=TSA\u30dd\u30ea\u30b7\u30fcOID:
+jfx.gui.tsa.hashAlgorithm=TSA\u30cf\u30c3\u30b7\u30e5\u30a2\u30eb\u30b4\u30ea\u30ba\u30e0:
+jfx.gui.tsa.enableOcsp=OCSP\u3092\u6709\u52b9\u306b\u3059\u308b
+jfx.gui.tsa.ocspServerUrl=OCSP\u30b5\u30fc\u30d0\u30fcURL:
+jfx.gui.tsa.enableCrl=CRL\u3092\u6709\u52b9\u306b\u3059\u308b
+jfx.gui.tsa.proxyType=\u30d7\u30ed\u30ad\u30b7\u30bf\u30a4\u30d7:
+jfx.gui.tsa.proxyHost=\u30d7\u30ed\u30ad\u30b7\u30db\u30b9\u30c8:
+jfx.gui.tsa.proxyPort=\u30d7\u30ed\u30ad\u30b7\u30dd\u30fc\u30c8:
+jfx.gui.console.title=\u51fa\u529b\u30b3\u30f3\u30bd\u30fc\u30eb
+jfx.gui.console.clear=\u30af\u30ea\u30a2
diff --git a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_nb-NO.properties b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_nb-NO.properties
index 2db04684..d0a2fe98 100644
--- a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_nb-NO.properties
+++ b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_nb-NO.properties
@@ -118,3 +118,103 @@ gui.storePasswords.checkbox=&Husk passord
gui.title=JsignPDF (versjon {0})
gui.vs.browse.button=Utforsk \u2026
gui.vs.close.button=Lukk
+#
+# JavaFX GUI
+#
+jfx.gui.menu.file=Fil
+jfx.gui.menu.file.open=\u00C5pne PDF...
+jfx.gui.menu.file.close=Lukk
+jfx.gui.menu.file.sign=Signer
+jfx.gui.menu.file.recentFiles=Nylige filer
+jfx.gui.menu.file.recentFiles.empty=Ingen nylige filer
+jfx.gui.menu.file.exit=Avslutt
+jfx.gui.menu.view=Visning
+jfx.gui.menu.view.zoomIn=Zoom inn
+jfx.gui.menu.view.zoomOut=Zoom ut
+jfx.gui.menu.view.fitPage=Tilpass side
+jfx.gui.menu.view.toggleSidePanel=Vis/skjul sidepanel
+jfx.gui.menu.signing=Signering
+jfx.gui.menu.help=Hjelp
+jfx.gui.menu.help.about=Om JSignPdf
+jfx.gui.toolbar.open=\u00C5pne
+jfx.gui.toolbar.fit=Tilpass
+jfx.gui.toolbar.sign=Signer
+jfx.gui.panel.certificate=Sertifikat
+jfx.gui.panel.signatureAppearance=Signaturutseende
+jfx.gui.panel.timestampValidation=Tidsstempel og validering
+jfx.gui.panel.encryptionRights=Kryptering og rettigheter
+jfx.gui.dropHint=Slipp en PDF-fil her eller bruk Fil > \u00C5pne
+jfx.gui.status.ready=Klar
+jfx.gui.status.signingInProgress=Signerer...
+jfx.gui.status.signingOk=Signering fullf\u00F8rt
+jfx.gui.status.signingFailed=Signering mislyktes
+jfx.gui.status.renderError=Feil ved visning av side
+jfx.gui.status.readError=Feil: Kan ikke lese PDF-filen
+jfx.gui.status.shiftToReplace=Hold Shift og dra for \u00e5 erstatte signaturrektangelet
+jfx.gui.dialog.signingComplete.title=Signering fullf\u00F8rt
+jfx.gui.dialog.signingComplete.text=PDF-filen er signert.
+jfx.gui.dialog.signingFailed.title=Signering mislyktes
+jfx.gui.dialog.signingFailed.text=Signeringsprosessen mislyktes. Sjekk utdatakonsollen.
+jfx.gui.dialog.signingError.title=Signeringsfeil
+jfx.gui.dialog.noDocument.title=Ingen dokument
+jfx.gui.dialog.noDocument.text=Vennligst \u00E5pne et PDF-dokument f\u00F8rst.
+jfx.gui.dialog.openPdf.title=\u00C5pne PDF
+jfx.gui.dialog.about.description=Et gratis program for PDF-signering.
+jfx.gui.dialog.selectKeystoreFile=Velg n\u00F8kkelknippefil
+jfx.gui.dialog.selectSignatureImage=Velg signaturbilde
+jfx.gui.dialog.selectBackgroundImage=Velg bakgrunnsbilde
+jfx.gui.dialog.selectOutputPdf=Velg utdata-PDF-fil
+jfx.gui.dialog.selectEncryptionCert=Velg krypteringssertifikat
+jfx.gui.dialog.selectTsaCertFile=Velg TSA-sertifikatfil
+jfx.gui.cert.keystoreType=N\u00F8kkelknippetype:
+jfx.gui.cert.keystoreFile=N\u00F8kkelknippefil:
+jfx.gui.cert.keystorePassword=N\u00F8kkelknippepassord:
+jfx.gui.cert.loadKeys=Last inn n\u00F8kler
+jfx.gui.cert.keyAlias=N\u00F8kkelalias:
+jfx.gui.cert.keyPassword=N\u00F8kkelpassord:
+jfx.gui.cert.storePasswords=Husk passord
+jfx.gui.sig.enableVisible=Aktiver synlig signatur
+jfx.gui.sig.renderMode=Visningsmodus:
+jfx.gui.sig.l2Text=Signaturtekst:
+jfx.gui.sig.l4Text=Statustekst:
+jfx.gui.sig.fontSize=Skriftst\u00F8rrelse:
+jfx.gui.sig.signatureImage=Signaturbilde:
+jfx.gui.sig.backgroundImage=Bakgrunnsbilde:
+jfx.gui.sig.acro6Layers=Acrobat 6-lagmodus
+jfx.gui.sig.hashAlgorithm=Sjekksumsalgoritme:
+jfx.gui.sig.certLevel=Sertifiseringsniv\u00E5:
+jfx.gui.sig.signerName=Signaturnavn:
+jfx.gui.sig.reason=Grunn:
+jfx.gui.sig.location=Sted:
+jfx.gui.sig.contact=Kontakt:
+jfx.gui.sig.appendSignature=Legg til signatur
+jfx.gui.sig.outputFile=Utdatafil:
+jfx.gui.enc.pdfEncryption=PDF-kryptering:
+jfx.gui.enc.ownerPassword=Eier-passord:
+jfx.gui.enc.userPassword=Brukerpassord:
+jfx.gui.enc.encryptionCert=Krypteringssertifikat:
+jfx.gui.enc.printRight=Utskriftsrettighet:
+jfx.gui.enc.allowCopy=Tillat kopiering
+jfx.gui.enc.allowAssembly=Tillat sammenstilling
+jfx.gui.enc.allowFillIn=Tillat utfylling
+jfx.gui.enc.allowScreenReaders=Tillat skjermlesere
+jfx.gui.enc.allowModifyAnnotations=Tillat endring av kommentarer
+jfx.gui.enc.allowModifyContents=Tillat endring av innhold
+jfx.gui.tsa.enableTimestamp=Aktiver tidsstempel (TSA)
+jfx.gui.tsa.serverUrl=TSA-nettadresse:
+jfx.gui.tsa.authentication=Identitetsbekreftelse:
+jfx.gui.tsa.user=TSA-bruker:
+jfx.gui.tsa.password=TSA-passord:
+jfx.gui.tsa.certFileType=TSA-sertifikatfiltype:
+jfx.gui.tsa.certFile=TSA-sertifikatfil:
+jfx.gui.tsa.certPassword=TSA-sertifikatpassord:
+jfx.gui.tsa.policyOid=TSA-praksis OID:
+jfx.gui.tsa.hashAlgorithm=TSA-sjekksumsalgoritme:
+jfx.gui.tsa.enableOcsp=Aktiver OCSP
+jfx.gui.tsa.ocspServerUrl=OCSP-nettadresse:
+jfx.gui.tsa.enableCrl=Aktiver CRL
+jfx.gui.tsa.proxyType=Mellomtjenertype:
+jfx.gui.tsa.proxyHost=Mellomtjener-vert:
+jfx.gui.tsa.proxyPort=Mellomtjener-port:
+jfx.gui.console.title=Utdatakonsoll
+jfx.gui.console.clear=T\u00F8m
diff --git a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_pl.properties b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_pl.properties
index 83b0e36c..7322eba5 100644
--- a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_pl.properties
+++ b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_pl.properties
@@ -128,3 +128,103 @@ default.l2text.date=Data:
default.l2text.location=Lokalizacja:
gui.hashAlgorithm.label=Algorytm &Hash
gui.pdfEncryption.label=Szyfrowanie PDF
+#
+# JavaFX GUI
+#
+jfx.gui.menu.file=Plik
+jfx.gui.menu.file.open=Otw\u00F3rz PDF...
+jfx.gui.menu.file.close=Zamknij
+jfx.gui.menu.file.sign=Podpisz
+jfx.gui.menu.file.recentFiles=Ostatnie pliki
+jfx.gui.menu.file.recentFiles.empty=Brak ostatnich plik\u00f3w
+jfx.gui.menu.file.exit=Wyj\u015Bcie
+jfx.gui.menu.view=Widok
+jfx.gui.menu.view.zoomIn=Powi\u0119ksz
+jfx.gui.menu.view.zoomOut=Pomniejsz
+jfx.gui.menu.view.fitPage=Dopasuj stron\u0119
+jfx.gui.menu.view.toggleSidePanel=Prze\u0142\u0105cz panel boczny
+jfx.gui.menu.signing=Podpisywanie
+jfx.gui.menu.help=Pomoc
+jfx.gui.menu.help.about=O programie JSignPdf
+jfx.gui.toolbar.open=Otw\u00F3rz
+jfx.gui.toolbar.fit=Dopasuj
+jfx.gui.toolbar.sign=Podpisz
+jfx.gui.panel.certificate=Certyfikat
+jfx.gui.panel.signatureAppearance=Wygl\u0105d podpisu
+jfx.gui.panel.timestampValidation=Znacznik czasu i walidacja
+jfx.gui.panel.encryptionRights=Szyfrowanie i uprawnienia
+jfx.gui.dropHint=Przeci\u0105gnij plik PDF tutaj lub u\u017Cyj Plik > Otw\u00F3rz
+jfx.gui.status.ready=Gotowy
+jfx.gui.status.signingInProgress=Podpisywanie...
+jfx.gui.status.signingOk=Podpisywanie zako\u0144czone pomy\u015Blnie
+jfx.gui.status.signingFailed=Podpisywanie nie powiod\u0142o si\u0119
+jfx.gui.status.renderError=B\u0142\u0105d renderowania strony
+jfx.gui.status.readError=B\u0142\u0105d: Nie mo\u017Cna odczyta\u0107 pliku PDF
+jfx.gui.status.shiftToReplace=Przytrzymaj Shift i przeci\u0105gnij, aby zast\u0105pi\u0107 prostok\u0105t podpisu
+jfx.gui.dialog.signingComplete.title=Podpisywanie zako\u0144czone
+jfx.gui.dialog.signingComplete.text=Plik PDF zosta\u0142 pomy\u015Blnie podpisany.
+jfx.gui.dialog.signingFailed.title=Podpisywanie nie powiod\u0142o si\u0119
+jfx.gui.dialog.signingFailed.text=Proces podpisywania nie powi\u00F3d\u0142 si\u0119. Sprawd\u017A konsol\u0119 wyj\u015Bciow\u0105.
+jfx.gui.dialog.signingError.title=B\u0142\u0105d podpisywania
+jfx.gui.dialog.noDocument.title=Brak dokumentu
+jfx.gui.dialog.noDocument.text=Najpierw otw\u00F3rz dokument PDF.
+jfx.gui.dialog.openPdf.title=Otw\u00F3rz PDF
+jfx.gui.dialog.about.description=Darmowa aplikacja do podpisywania PDF.
+jfx.gui.dialog.selectKeystoreFile=Wybierz plik keystore
+jfx.gui.dialog.selectSignatureImage=Wybierz obraz podpisu
+jfx.gui.dialog.selectBackgroundImage=Wybierz obraz t\u0142a
+jfx.gui.dialog.selectOutputPdf=Wybierz wyj\u015Bciowy plik PDF
+jfx.gui.dialog.selectEncryptionCert=Wybierz certyfikat szyfrowania
+jfx.gui.dialog.selectTsaCertFile=Wybierz plik certyfikatu TSA
+jfx.gui.cert.keystoreType=Typ keystore:
+jfx.gui.cert.keystoreFile=Plik keystore:
+jfx.gui.cert.keystorePassword=Has\u0142o keystore:
+jfx.gui.cert.loadKeys=Wczytaj klucze
+jfx.gui.cert.keyAlias=Alias klucza:
+jfx.gui.cert.keyPassword=Has\u0142o klucza:
+jfx.gui.cert.storePasswords=Zapami\u0119taj has\u0142a
+jfx.gui.sig.enableVisible=W\u0142\u0105cz widoczn\u0105 sygnatur\u0119
+jfx.gui.sig.renderMode=Spos\u00F3b renderowania:
+jfx.gui.sig.l2Text=Tekst sygnatury:
+jfx.gui.sig.l4Text=Tekst statusu:
+jfx.gui.sig.fontSize=Wielko\u015B\u0107 czcionki:
+jfx.gui.sig.signatureImage=Obraz sygnatury:
+jfx.gui.sig.backgroundImage=Obraz t\u0142a:
+jfx.gui.sig.acro6Layers=Tryb warstw Acrobat 6
+jfx.gui.sig.hashAlgorithm=Algorytm Hash:
+jfx.gui.sig.certLevel=Poziom certyfikacji:
+jfx.gui.sig.signerName=Nazwa podpisuj\u0105cego:
+jfx.gui.sig.reason=Pow\u00F3d:
+jfx.gui.sig.location=Miejsce:
+jfx.gui.sig.contact=Kontakt:
+jfx.gui.sig.appendSignature=Do\u0142\u0105cz sygnatur\u0119
+jfx.gui.sig.outputFile=Plik wyj\u015Bciowy:
+jfx.gui.enc.pdfEncryption=Szyfrowanie PDF:
+jfx.gui.enc.ownerPassword=Has\u0142o w\u0142a\u015Bciciela:
+jfx.gui.enc.userPassword=Has\u0142o u\u017Cytkownika:
+jfx.gui.enc.encryptionCert=Certyfikat szyfrowania:
+jfx.gui.enc.printRight=Prawo drukowania:
+jfx.gui.enc.allowCopy=Zezw\u00F3l na kopiowanie
+jfx.gui.enc.allowAssembly=Zezw\u00F3l na kompilacj\u0119
+jfx.gui.enc.allowFillIn=Zezw\u00F3l na wype\u0142nianie
+jfx.gui.enc.allowScreenReaders=Zezw\u00F3l na czytniki ekranu
+jfx.gui.enc.allowModifyAnnotations=Zezw\u00F3l na zmian\u0119 komentarzy
+jfx.gui.enc.allowModifyContents=Zezw\u00F3l na zmian\u0119 tre\u015Bci
+jfx.gui.tsa.enableTimestamp=W\u0142\u0105cz znacznik czasu (TSA)
+jfx.gui.tsa.serverUrl=URL serwera TSA:
+jfx.gui.tsa.authentication=Autoryzacja:
+jfx.gui.tsa.user=U\u017Cytkownik TSA:
+jfx.gui.tsa.password=Has\u0142o TSA:
+jfx.gui.tsa.certFileType=Typ pliku certyfikatu TSA:
+jfx.gui.tsa.certFile=Plik certyfikatu TSA:
+jfx.gui.tsa.certPassword=Has\u0142o certyfikatu TSA:
+jfx.gui.tsa.policyOid=OID polityki TSA:
+jfx.gui.tsa.hashAlgorithm=Algorytm Hash TSA:
+jfx.gui.tsa.enableOcsp=W\u0142\u0105cz OCSP
+jfx.gui.tsa.ocspServerUrl=URL serwera OCSP:
+jfx.gui.tsa.enableCrl=W\u0142\u0105cz CRL
+jfx.gui.tsa.proxyType=Rodzaj proxy:
+jfx.gui.tsa.proxyHost=Host proxy:
+jfx.gui.tsa.proxyPort=Port proxy:
+jfx.gui.console.title=Konsola wyj\u015Bciowa
+jfx.gui.console.clear=Wyczy\u015B\u0107
diff --git a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_pt.properties b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_pt.properties
index 6de7bdda..e76d3848 100644
--- a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_pt.properties
+++ b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_pt.properties
@@ -256,3 +256,103 @@ extcsp.nosignature=Erro ao assinar, assinatura n\u00E3o recebida, sem detalhes
hlp.gui=(beta) mostrar GUI mesmo quando outros argumentos de linha de comando s\u00E3o fornecidos
#console.updateVersionNotPossibleInAppendMode=Choosen configuration requires PDF version update, but it's not possible in the "append" signature mode.
console.updateVersionNotPossibleInAppendModeForGivenHash=O algoritmo de hash escolhido ({0}) requer uma vers\u00E3o PDF mais recente ({1}) do que a original ({2}). A atualiza\u00E7\u00E3o da vers\u00E3o em PDF \u00E9 imposs\u00EDvel no modo de assinatura "acrescentar". Desative o modo de acr\u00E9scimo ou escolha outro algoritmo de hash. Estes s\u00E3o os requisitos do algoritmo: {3}
+#
+# JavaFX GUI
+#
+jfx.gui.menu.file=Ficheiro
+jfx.gui.menu.file.open=Abrir PDF...
+jfx.gui.menu.file.close=Fechar
+jfx.gui.menu.file.sign=Assinar
+jfx.gui.menu.file.recentFiles=Ficheiros recentes
+jfx.gui.menu.file.recentFiles.empty=Sem ficheiros recentes
+jfx.gui.menu.file.exit=Sair
+jfx.gui.menu.view=Ver
+jfx.gui.menu.view.zoomIn=Ampliar
+jfx.gui.menu.view.zoomOut=Reduzir
+jfx.gui.menu.view.fitPage=Ajustar \u00e0 p\u00e1gina
+jfx.gui.menu.view.toggleSidePanel=Alternar painel lateral
+jfx.gui.menu.signing=Assinatura
+jfx.gui.menu.help=Ajuda
+jfx.gui.menu.help.about=Sobre o JSignPdf
+jfx.gui.toolbar.open=Abrir
+jfx.gui.toolbar.fit=Ajustar
+jfx.gui.toolbar.sign=Assinar
+jfx.gui.panel.certificate=Certificado
+jfx.gui.panel.signatureAppearance=Apar\u00eancia da assinatura
+jfx.gui.panel.timestampValidation=Carimbo temporal e valida\u00e7\u00e3o
+jfx.gui.panel.encryptionRights=Encripta\u00e7\u00e3o e direitos
+jfx.gui.dropHint=Arraste um ficheiro PDF para aqui ou use Ficheiro > Abrir
+jfx.gui.status.ready=Pronto
+jfx.gui.status.signingInProgress=A assinar...
+jfx.gui.status.signingOk=Assinatura conclu\u00edda com sucesso
+jfx.gui.status.signingFailed=A assinatura falhou
+jfx.gui.status.renderError=Erro ao renderizar a p\u00e1gina
+jfx.gui.status.readError=Erro: n\u00e3o \u00e9 poss\u00edvel ler o ficheiro PDF
+jfx.gui.status.shiftToReplace=Mantenha Shift e arraste para substituir o ret\u00e2ngulo da assinatura
+jfx.gui.dialog.signingComplete.title=Assinatura conclu\u00edda
+jfx.gui.dialog.signingComplete.text=O PDF foi assinado com sucesso.
+jfx.gui.dialog.signingFailed.title=Assinatura falhada
+jfx.gui.dialog.signingFailed.text=A assinatura falhou. Verifique a consola de sa\u00edda para mais detalhes.
+jfx.gui.dialog.signingError.title=Erro de assinatura
+jfx.gui.dialog.noDocument.title=Sem documento
+jfx.gui.dialog.noDocument.text=Por favor, abra primeiro um documento PDF.
+jfx.gui.dialog.openPdf.title=Abrir PDF
+jfx.gui.dialog.about.description=Aplica\u00e7\u00e3o gratuita para assinar ficheiros PDF.
+jfx.gui.dialog.selectKeystoreFile=Selecionar ficheiro de keystore
+jfx.gui.dialog.selectSignatureImage=Selecionar imagem de assinatura
+jfx.gui.dialog.selectBackgroundImage=Selecionar imagem de fundo
+jfx.gui.dialog.selectOutputPdf=Selecionar ficheiro PDF de sa\u00edda
+jfx.gui.dialog.selectEncryptionCert=Selecionar certificado de encripta\u00e7\u00e3o
+jfx.gui.dialog.selectTsaCertFile=Selecionar ficheiro de certificado TSA
+jfx.gui.cert.keystoreType=Tipo de keystore:
+jfx.gui.cert.keystoreFile=Ficheiro de keystore:
+jfx.gui.cert.keystorePassword=Palavra-passe do keystore:
+jfx.gui.cert.loadKeys=Carregar chaves
+jfx.gui.cert.keyAlias=Alias da chave:
+jfx.gui.cert.keyPassword=Palavra-passe da chave:
+jfx.gui.cert.storePasswords=Guardar palavras-passe
+jfx.gui.sig.enableVisible=Ativar assinatura vis\u00edvel
+jfx.gui.sig.renderMode=Modo de visualiza\u00e7\u00e3o:
+jfx.gui.sig.l2Text=Texto da assinatura:
+jfx.gui.sig.l4Text=Texto de estado:
+jfx.gui.sig.fontSize=Tamanho da fonte:
+jfx.gui.sig.signatureImage=Imagem de assinatura:
+jfx.gui.sig.backgroundImage=Imagem de fundo:
+jfx.gui.sig.acro6Layers=Modo de camadas Acrobat 6
+jfx.gui.sig.hashAlgorithm=Algoritmo de hash:
+jfx.gui.sig.certLevel=N\u00edvel de certifica\u00e7\u00e3o:
+jfx.gui.sig.signerName=Nome do assinante:
+jfx.gui.sig.reason=Motivo:
+jfx.gui.sig.location=Localiza\u00e7\u00e3o:
+jfx.gui.sig.contact=Contacto:
+jfx.gui.sig.appendSignature=Adicionar assinatura
+jfx.gui.sig.outputFile=Ficheiro de sa\u00edda:
+jfx.gui.enc.pdfEncryption=Encripta\u00e7\u00e3o PDF:
+jfx.gui.enc.ownerPassword=Palavra-passe do propriet\u00e1rio:
+jfx.gui.enc.userPassword=Palavra-passe do utilizador:
+jfx.gui.enc.encryptionCert=Certificado de encripta\u00e7\u00e3o:
+jfx.gui.enc.printRight=Direito de impress\u00e3o:
+jfx.gui.enc.allowCopy=Permitir c\u00f3pia
+jfx.gui.enc.allowAssembly=Permitir montagem
+jfx.gui.enc.allowFillIn=Permitir preenchimento
+jfx.gui.enc.allowScreenReaders=Permitir leitores de ecr\u00e3
+jfx.gui.enc.allowModifyAnnotations=Permitir modificar anota\u00e7\u00f5es
+jfx.gui.enc.allowModifyContents=Permitir modificar conte\u00fado
+jfx.gui.tsa.enableTimestamp=Ativar carimbo temporal (TSA)
+jfx.gui.tsa.serverUrl=URL do servidor TSA:
+jfx.gui.tsa.authentication=Autentica\u00e7\u00e3o:
+jfx.gui.tsa.user=Utilizador TSA:
+jfx.gui.tsa.password=Palavra-passe TSA:
+jfx.gui.tsa.certFileType=Tipo de ficheiro do certificado TSA:
+jfx.gui.tsa.certFile=Ficheiro de certificado TSA:
+jfx.gui.tsa.certPassword=Palavra-passe do certificado TSA:
+jfx.gui.tsa.policyOid=OID da pol\u00edtica TSA:
+jfx.gui.tsa.hashAlgorithm=Algoritmo de hash TSA:
+jfx.gui.tsa.enableOcsp=Ativar OCSP
+jfx.gui.tsa.ocspServerUrl=URL do servidor OCSP:
+jfx.gui.tsa.enableCrl=Ativar CRL
+jfx.gui.tsa.proxyType=Tipo de proxy:
+jfx.gui.tsa.proxyHost=Servidor proxy:
+jfx.gui.tsa.proxyPort=Porta do proxy:
+jfx.gui.console.title=Consola de sa\u00edda
+jfx.gui.console.clear=Limpar
diff --git a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_ru.properties b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_ru.properties
index 36928b25..145366bc 100644
--- a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_ru.properties
+++ b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_ru.properties
@@ -16,3 +16,103 @@ gui.info.close.button=\u0417\u0430\u043A\u0440\u044B\u0442\u044C
default.l2text.reason=\u041F\u0440\u0438\u0447\u0438\u043D\u0430:
default.l2text.location=\u0420\u0430\u0441\u043F\u043E\u043B\u043E\u0436\u0435\u043D\u0438\u0435:
default.l2text.date=\u0414\u0430\u0442\u0430:
+#
+# JavaFX GUI
+#
+jfx.gui.menu.file=\u0424\u0430\u0439\u043B
+jfx.gui.menu.file.open=\u041E\u0442\u043A\u0440\u044B\u0442\u044C PDF...
+jfx.gui.menu.file.close=\u0417\u0430\u043A\u0440\u044B\u0442\u044C
+jfx.gui.menu.file.sign=\u041F\u043E\u0434\u043F\u0438\u0441\u0430\u0442\u044C
+jfx.gui.menu.file.recentFiles=\u041d\u0435\u0434\u0430\u0432\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u044b
+jfx.gui.menu.file.recentFiles.empty=\u041d\u0435\u0442 \u043d\u0435\u0434\u0430\u0432\u043d\u0438\u0445 \u0444\u0430\u0439\u043b\u043e\u0432
+jfx.gui.menu.file.exit=\u0412\u044B\u0445\u043E\u0434
+jfx.gui.menu.view=\u0412\u0438\u0434
+jfx.gui.menu.view.zoomIn=\u0423\u0432\u0435\u043B\u0438\u0447\u0438\u0442\u044C
+jfx.gui.menu.view.zoomOut=\u0423\u043C\u0435\u043D\u044C\u0448\u0438\u0442\u044C
+jfx.gui.menu.view.fitPage=\u041F\u043E \u0440\u0430\u0437\u043C\u0435\u0440\u0443 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B
+jfx.gui.menu.view.toggleSidePanel=\u041F\u0435\u0440\u0435\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u0431\u043E\u043A\u043E\u0432\u0443\u044E \u043F\u0430\u043D\u0435\u043B\u044C
+jfx.gui.menu.signing=\u041F\u043E\u0434\u043F\u0438\u0441\u0430\u043D\u0438\u0435
+jfx.gui.menu.help=\u041F\u043E\u043C\u043E\u0449\u044C
+jfx.gui.menu.help.about=\u041E \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u0435 JSignPdf
+jfx.gui.toolbar.open=\u041E\u0442\u043A\u0440\u044B\u0442\u044C
+jfx.gui.toolbar.fit=\u041F\u043E\u0434\u043E\u0433\u043D\u0430\u0442\u044C
+jfx.gui.toolbar.sign=\u041F\u043E\u0434\u043F\u0438\u0441\u0430\u0442\u044C
+jfx.gui.panel.certificate=\u0421\u0435\u0440\u0442\u0438\u0444\u0438\u043A\u0430\u0442
+jfx.gui.panel.signatureAppearance=\u0412\u043D\u0435\u0448\u043D\u0438\u0439 \u0432\u0438\u0434 \u043F\u043E\u0434\u043F\u0438\u0441\u0438
+jfx.gui.panel.timestampValidation=\u041C\u0435\u0442\u043A\u0430 \u0432\u0440\u0435\u043C\u0435\u043D\u0438 \u0438 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0430
+jfx.gui.panel.encryptionRights=\u0428\u0438\u0444\u0440\u043E\u0432\u0430\u043D\u0438\u0435 \u0438 \u043F\u0440\u0430\u0432\u0430
+jfx.gui.dropHint=\u041F\u0435\u0440\u0435\u0442\u0430\u0449\u0438\u0442\u0435 PDF \u0444\u0430\u0439\u043B \u0441\u044E\u0434\u0430 \u0438\u043B\u0438 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439\u0442\u0435 \u0424\u0430\u0439\u043B > \u041E\u0442\u043A\u0440\u044B\u0442\u044C
+jfx.gui.status.ready=\u0413\u043E\u0442\u043E\u0432\u043E
+jfx.gui.status.signingInProgress=\u041F\u043E\u0434\u043F\u0438\u0441\u0430\u043D\u0438\u0435...
+jfx.gui.status.signingOk=\u041F\u043E\u0434\u043F\u0438\u0441\u0430\u043D\u0438\u0435 \u0443\u0441\u043F\u0435\u0448\u043D\u043E \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u043E
+jfx.gui.status.signingFailed=\u041E\u0448\u0438\u0431\u043A\u0430 \u043F\u043E\u0434\u043F\u0438\u0441\u0430\u043D\u0438\u044F
+jfx.gui.status.renderError=\u041E\u0448\u0438\u0431\u043A\u0430 \u043E\u0442\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u044F \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B
+jfx.gui.status.readError=\u041E\u0448\u0438\u0431\u043A\u0430: \u041D\u0435\u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u0442\u044C PDF \u0444\u0430\u0439\u043B
+jfx.gui.status.shiftToReplace=\u0423\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0439\u0442\u0435 Shift \u0438 \u043f\u0435\u0440\u0435\u0442\u0430\u0449\u0438\u0442\u0435, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u043f\u0440\u044f\u043c\u043e\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a \u043f\u043e\u0434\u043f\u0438\u0441\u0438
+jfx.gui.dialog.signingComplete.title=\u041F\u043E\u0434\u043F\u0438\u0441\u0430\u043D\u0438\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u043E
+jfx.gui.dialog.signingComplete.text=PDF \u0444\u0430\u0439\u043B \u0443\u0441\u043F\u0435\u0448\u043D\u043E \u043F\u043E\u0434\u043F\u0438\u0441\u0430\u043D.
+jfx.gui.dialog.signingFailed.title=\u041E\u0448\u0438\u0431\u043A\u0430 \u043F\u043E\u0434\u043F\u0438\u0441\u0430\u043D\u0438\u044F
+jfx.gui.dialog.signingFailed.text=\u041F\u0440\u043E\u0446\u0435\u0441\u0441 \u043F\u043E\u0434\u043F\u0438\u0441\u0430\u043D\u0438\u044F \u043D\u0435 \u0443\u0434\u0430\u043B\u0441\u044F. \u041F\u0440\u043E\u0432\u0435\u0440\u044C\u0442\u0435 \u043A\u043E\u043D\u0441\u043E\u043B\u044C \u0432\u044B\u0432\u043E\u0434\u0430.
+jfx.gui.dialog.signingError.title=\u041E\u0448\u0438\u0431\u043A\u0430 \u043F\u043E\u0434\u043F\u0438\u0441\u0430\u043D\u0438\u044F
+jfx.gui.dialog.noDocument.title=\u041D\u0435\u0442 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430
+jfx.gui.dialog.noDocument.text=\u0421\u043D\u0430\u0447\u0430\u043B\u0430 \u043E\u0442\u043A\u0440\u043E\u0439\u0442\u0435 PDF \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442.
+jfx.gui.dialog.openPdf.title=\u041E\u0442\u043A\u0440\u044B\u0442\u044C PDF
+jfx.gui.dialog.about.description=\u0411\u0435\u0441\u043F\u043B\u0430\u0442\u043D\u043E\u0435 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u0434\u043B\u044F \u043F\u043E\u0434\u043F\u0438\u0441\u0430\u043D\u0438\u044F PDF.
+jfx.gui.dialog.selectKeystoreFile=\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0444\u0430\u0439\u043B \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0430 \u043A\u043B\u044E\u0447\u0435\u0439
+jfx.gui.dialog.selectSignatureImage=\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435 \u043F\u043E\u0434\u043F\u0438\u0441\u0438
+jfx.gui.dialog.selectBackgroundImage=\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0444\u043E\u043D\u043E\u0432\u043E\u0435 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435
+jfx.gui.dialog.selectOutputPdf=\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0432\u044B\u0445\u043E\u0434\u043D\u043E\u0439 PDF \u0444\u0430\u0439\u043B
+jfx.gui.dialog.selectEncryptionCert=\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043A\u0430\u0442 \u0448\u0438\u0444\u0440\u043E\u0432\u0430\u043D\u0438\u044F
+jfx.gui.dialog.selectTsaCertFile=\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0444\u0430\u0439\u043B \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u0430 TSA
+jfx.gui.cert.keystoreType=\u0422\u0438\u043F \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0430 \u043A\u043B\u044E\u0447\u0435\u0439:
+jfx.gui.cert.keystoreFile=\u0424\u0430\u0439\u043B \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0430 \u043A\u043B\u044E\u0447\u0435\u0439:
+jfx.gui.cert.keystorePassword=\u041F\u0430\u0440\u043E\u043B\u044C \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0430 \u043A\u043B\u044E\u0447\u0435\u0439:
+jfx.gui.cert.loadKeys=\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u043A\u043B\u044E\u0447\u0438
+jfx.gui.cert.keyAlias=\u041F\u0441\u0435\u0432\u0434\u043E\u043D\u0438\u043C \u043A\u043B\u044E\u0447\u0430:
+jfx.gui.cert.keyPassword=\u041F\u0430\u0440\u043E\u043B\u044C \u043A\u043B\u044E\u0447\u0430:
+jfx.gui.cert.storePasswords=\u0417\u0430\u043F\u043E\u043C\u043D\u0438\u0442\u044C \u043F\u0430\u0440\u043E\u043B\u0438
+jfx.gui.sig.enableVisible=\u0412\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u0432\u0438\u0434\u0438\u043C\u0443\u044E \u043F\u043E\u0434\u043F\u0438\u0441\u044C
+jfx.gui.sig.renderMode=\u0420\u0435\u0436\u0438\u043C \u043E\u0442\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u044F:
+jfx.gui.sig.l2Text=\u0422\u0435\u043A\u0441\u0442 \u043F\u043E\u0434\u043F\u0438\u0441\u0438:
+jfx.gui.sig.l4Text=\u0422\u0435\u043A\u0441\u0442 \u0441\u0442\u0430\u0442\u0443\u0441\u0430:
+jfx.gui.sig.fontSize=\u0420\u0430\u0437\u043C\u0435\u0440 \u0448\u0440\u0438\u0444\u0442\u0430:
+jfx.gui.sig.signatureImage=\u0418\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435 \u043F\u043E\u0434\u043F\u0438\u0441\u0438:
+jfx.gui.sig.backgroundImage=\u0424\u043E\u043D\u043E\u0432\u043E\u0435 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435:
+jfx.gui.sig.acro6Layers=\u0420\u0435\u0436\u0438\u043C \u0441\u043B\u043E\u0451\u0432 Acrobat 6
+jfx.gui.sig.hashAlgorithm=\u0410\u043B\u0433\u043E\u0440\u0438\u0442\u043C \u0445\u0435\u0448\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u044F:
+jfx.gui.sig.certLevel=\u0423\u0440\u043E\u0432\u0435\u043D\u044C \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438:
+jfx.gui.sig.signerName=\u0418\u043C\u044F \u043F\u043E\u0434\u043F\u0438\u0441\u0430\u043D\u0442\u0430:
+jfx.gui.sig.reason=\u041F\u0440\u0438\u0447\u0438\u043D\u0430:
+jfx.gui.sig.location=\u0420\u0430\u0441\u043F\u043E\u043B\u043E\u0436\u0435\u043D\u0438\u0435:
+jfx.gui.sig.contact=\u041A\u043E\u043D\u0442\u0430\u043A\u0442:
+jfx.gui.sig.appendSignature=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u043F\u043E\u0434\u043F\u0438\u0441\u044C
+jfx.gui.sig.outputFile=\u0412\u044B\u0445\u043E\u0434\u043D\u043E\u0439 \u0444\u0430\u0439\u043B:
+jfx.gui.enc.pdfEncryption=\u0428\u0438\u0444\u0440\u043E\u0432\u0430\u043D\u0438\u0435 PDF:
+jfx.gui.enc.ownerPassword=\u041F\u0430\u0440\u043E\u043B\u044C \u0432\u043B\u0430\u0434\u0435\u043B\u044C\u0446\u0430:
+jfx.gui.enc.userPassword=\u041F\u0430\u0440\u043E\u043B\u044C \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F:
+jfx.gui.enc.encryptionCert=\u0421\u0435\u0440\u0442\u0438\u0444\u0438\u043A\u0430\u0442 \u0448\u0438\u0444\u0440\u043E\u0432\u0430\u043D\u0438\u044F:
+jfx.gui.enc.printRight=\u041F\u0440\u0430\u0432\u043E \u043F\u0435\u0447\u0430\u0442\u0438:
+jfx.gui.enc.allowCopy=\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044C \u043A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u0435
+jfx.gui.enc.allowAssembly=\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044C \u0441\u0431\u043E\u0440\u043A\u0443
+jfx.gui.enc.allowFillIn=\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044C \u0437\u0430\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u0435
+jfx.gui.enc.allowScreenReaders=\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044C \u044D\u043A\u0440\u0430\u043D\u043D\u044B\u0435 \u0434\u0438\u043A\u0442\u043E\u0440\u044B
+jfx.gui.enc.allowModifyAnnotations=\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044C \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u0435 \u0430\u043D\u043D\u043E\u0442\u0430\u0446\u0438\u0439
+jfx.gui.enc.allowModifyContents=\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044C \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u0435 \u0441\u043E\u0434\u0435\u0440\u0436\u0438\u043C\u043E\u0433\u043E
+jfx.gui.tsa.enableTimestamp=\u0412\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u043C\u0435\u0442\u043A\u0443 \u0432\u0440\u0435\u043C\u0435\u043D\u0438 (TSA)
+jfx.gui.tsa.serverUrl=URL \u0441\u0435\u0440\u0432\u0435\u0440\u0430 TSA:
+jfx.gui.tsa.authentication=\u0410\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u044F:
+jfx.gui.tsa.user=\u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C TSA:
+jfx.gui.tsa.password=\u041F\u0430\u0440\u043E\u043B\u044C TSA:
+jfx.gui.tsa.certFileType=\u0422\u0438\u043F \u0444\u0430\u0439\u043B\u0430 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u0430 TSA:
+jfx.gui.tsa.certFile=\u0424\u0430\u0439\u043B \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u0430 TSA:
+jfx.gui.tsa.certPassword=\u041F\u0430\u0440\u043E\u043B\u044C \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u0430 TSA:
+jfx.gui.tsa.policyOid=OID \u043F\u043E\u043B\u0438\u0442\u0438\u043A\u0438 TSA:
+jfx.gui.tsa.hashAlgorithm=\u0410\u043B\u0433\u043E\u0440\u0438\u0442\u043C \u0445\u0435\u0448\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u044F TSA:
+jfx.gui.tsa.enableOcsp=\u0412\u043A\u043B\u044E\u0447\u0438\u0442\u044C OCSP
+jfx.gui.tsa.ocspServerUrl=URL \u0441\u0435\u0440\u0432\u0435\u0440\u0430 OCSP:
+jfx.gui.tsa.enableCrl=\u0412\u043A\u043B\u044E\u0447\u0438\u0442\u044C CRL
+jfx.gui.tsa.proxyType=\u0422\u0438\u043F \u043F\u0440\u043E\u043A\u0441\u0438:
+jfx.gui.tsa.proxyHost=\u0425\u043E\u0441\u0442 \u043F\u0440\u043E\u043A\u0441\u0438:
+jfx.gui.tsa.proxyPort=\u041F\u043E\u0440\u0442 \u043F\u0440\u043E\u043A\u0441\u0438:
+jfx.gui.console.title=\u041A\u043E\u043D\u0441\u043E\u043B\u044C \u0432\u044B\u0432\u043E\u0434\u0430
+jfx.gui.console.clear=\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u044C
diff --git a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_sk.properties b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_sk.properties
index b6a0a75b..624fd926 100644
--- a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_sk.properties
+++ b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_sk.properties
@@ -256,3 +256,103 @@ hlp.printRight=opr\u00E1vnenia na tla\u010D. Pou\u017E\u00EDva sa pre za\u0161if
gui.title=JSignPdf (verzia {0})
serverAuthn.certificate=Klientsk\u00FD certifik\u00E1t
ssl.keymanager.init=Inicializ\u00E1cia spr\u00E1vcu k\u013E\u00FA\u010Dov zo s\u00FAboru \u00FAlo\u017Eiska k\u013E\u00FA\u010Dov {0}.
+#
+# JavaFX GUI
+#
+jfx.gui.menu.file=S\u00FAbor
+jfx.gui.menu.file.open=Otvori\u0165 PDF...
+jfx.gui.menu.file.close=Zatvori\u0165
+jfx.gui.menu.file.sign=Podp\u00EDsa\u0165
+jfx.gui.menu.file.recentFiles=Ned\u00e1vne s\u00fabory
+jfx.gui.menu.file.recentFiles.empty=\u017diadne ned\u00e1vne s\u00fabory
+jfx.gui.menu.file.exit=Ukon\u010Di\u0165
+jfx.gui.menu.view=Zobrazenie
+jfx.gui.menu.view.zoomIn=Pribl\u00ED\u017Ei\u0165
+jfx.gui.menu.view.zoomOut=Oddiali\u0165
+jfx.gui.menu.view.fitPage=Prisp\u00F4sobi\u0165 str\u00E1nku
+jfx.gui.menu.view.toggleSidePanel=Prepn\u00FA\u0165 bo\u010Dn\u00FD panel
+jfx.gui.menu.signing=Podpisovanie
+jfx.gui.menu.help=Pomoc
+jfx.gui.menu.help.about=O programe JSignPdf
+jfx.gui.toolbar.open=Otvori\u0165
+jfx.gui.toolbar.fit=Prisp\u00F4sobi\u0165
+jfx.gui.toolbar.sign=Podp\u00EDsa\u0165
+jfx.gui.panel.certificate=Certifik\u00E1t
+jfx.gui.panel.signatureAppearance=Vzh\u013Ead podpisu
+jfx.gui.panel.timestampValidation=\u010Casov\u00E1 pe\u010Diatka a valid\u00E1cia
+jfx.gui.panel.encryptionRights=\u0160ifrovanie a pr\u00E1va
+jfx.gui.dropHint=Pretiahnite PDF s\u00FAbor sem alebo pou\u017Eite S\u00FAbor > Otvori\u0165
+jfx.gui.status.ready=Pripraven\u00FD
+jfx.gui.status.signingInProgress=Podpisovanie...
+jfx.gui.status.signingOk=Podpisovanie \u00FAspe\u0161ne dokon\u010Den\u00E9
+jfx.gui.status.signingFailed=Podpisovanie zlyhalo
+jfx.gui.status.renderError=Chyba pri vykres\u013Eovan\u00ED str\u00E1nky
+jfx.gui.status.readError=Chyba: Nie je mo\u017En\u00E9 pre\u010D\u00EDta\u0165 PDF s\u00FAbor
+jfx.gui.status.shiftToReplace=Dr\u017ete Shift a \u0165ahan\u00edm nahrad\u00edte obd\u013a\u017enik podpisu
+jfx.gui.dialog.signingComplete.title=Podpisovanie dokon\u010Den\u00E9
+jfx.gui.dialog.signingComplete.text=PDF s\u00FAbor bol \u00FAspe\u0161ne podp\u00EDsan\u00FD.
+jfx.gui.dialog.signingFailed.title=Podpisovanie zlyhalo
+jfx.gui.dialog.signingFailed.text=Proces podpisovania zlyhal. Skontrolujte v\u00FDstupn\u00FA konzolu.
+jfx.gui.dialog.signingError.title=Chyba podpisovania
+jfx.gui.dialog.noDocument.title=\u017Diadny dokument
+jfx.gui.dialog.noDocument.text=Najsk\u00F4r otvorte PDF dokument.
+jfx.gui.dialog.openPdf.title=Otvori\u0165 PDF
+jfx.gui.dialog.about.description=Bezplatn\u00E1 aplik\u00E1cia na podpisovanie PDF.
+jfx.gui.dialog.selectKeystoreFile=Vybra\u0165 s\u00FAbor \u00FAlo\u017Eiska k\u013E\u00FA\u010Dov
+jfx.gui.dialog.selectSignatureImage=Vybra\u0165 obr\u00E1zok podpisu
+jfx.gui.dialog.selectBackgroundImage=Vybra\u0165 obr\u00E1zok pozadia
+jfx.gui.dialog.selectOutputPdf=Vybra\u0165 v\u00FDstupn\u00FD PDF s\u00FAbor
+jfx.gui.dialog.selectEncryptionCert=Vybra\u0165 certifik\u00E1t pre \u0161ifrovanie
+jfx.gui.dialog.selectTsaCertFile=Vybra\u0165 s\u00FAbor certifik\u00E1tu TSA
+jfx.gui.cert.keystoreType=Typ \u00FAlo\u017Eiska k\u013E\u00FA\u010Dov:
+jfx.gui.cert.keystoreFile=S\u00FAbor \u00FAlo\u017Eiska k\u013E\u00FA\u010Dov:
+jfx.gui.cert.keystorePassword=Heslo \u00FAlo\u017Eiska k\u013E\u00FA\u010Dov:
+jfx.gui.cert.loadKeys=Na\u010D\u00EDta\u0165 k\u013E\u00FA\u010De
+jfx.gui.cert.keyAlias=Alias k\u013E\u00FA\u010Da:
+jfx.gui.cert.keyPassword=Heslo k\u013E\u00FA\u010Da:
+jfx.gui.cert.storePasswords=Zapam\u00E4ta\u0165 hesl\u00E1
+jfx.gui.sig.enableVisible=Povoli\u0165 vidite\u013En\u00FD podpis
+jfx.gui.sig.renderMode=Re\u017Eim zobrazovania:
+jfx.gui.sig.l2Text=Text podpisu:
+jfx.gui.sig.l4Text=Text stavu:
+jfx.gui.sig.fontSize=Ve\u013Ekos\u0165 p\u00EDsma:
+jfx.gui.sig.signatureImage=Obr\u00E1zok podpisu:
+jfx.gui.sig.backgroundImage=Obr\u00E1zok pozadia:
+jfx.gui.sig.acro6Layers=Re\u017Eim vrstiev Acrobat 6
+jfx.gui.sig.hashAlgorithm=Hashovac\u00ED algoritmus:
+jfx.gui.sig.certLevel=\u00DArove\u0148 certifik\u00E1cie:
+jfx.gui.sig.signerName=Meno podpisuj\u00FAceho:
+jfx.gui.sig.reason=D\u00F4vod:
+jfx.gui.sig.location=Lokalita:
+jfx.gui.sig.contact=Kontakt:
+jfx.gui.sig.appendSignature=Prida\u0165 podpis
+jfx.gui.sig.outputFile=V\u00FDstupn\u00FD s\u00FAbor:
+jfx.gui.enc.pdfEncryption=PDF \u0161ifrovanie:
+jfx.gui.enc.ownerPassword=Heslo vlastn\u00EDka:
+jfx.gui.enc.userPassword=Heslo pou\u017E\u00EDvate\u013Ea:
+jfx.gui.enc.encryptionCert=Certifik\u00E1t pre \u0161ifrovanie:
+jfx.gui.enc.printRight=Pr\u00E1vo na tla\u010D:
+jfx.gui.enc.allowCopy=Povoli\u0165 kop\u00EDrovanie
+jfx.gui.enc.allowAssembly=Povoli\u0165 zostavovanie
+jfx.gui.enc.allowFillIn=Povoli\u0165 vyp\u013A\u0148anie
+jfx.gui.enc.allowScreenReaders=Povoli\u0165 \u010D\u00EDta\u010Dky obrazovky
+jfx.gui.enc.allowModifyAnnotations=Povoli\u0165 zmenu pozn\u00E1mok
+jfx.gui.enc.allowModifyContents=Povoli\u0165 zmenu obsahu
+jfx.gui.tsa.enableTimestamp=Povoli\u0165 \u010Dasov\u00FA pe\u010Diatku (TSA)
+jfx.gui.tsa.serverUrl=URL servera TSA:
+jfx.gui.tsa.authentication=Autentifik\u00E1cia:
+jfx.gui.tsa.user=TSA pou\u017E\u00EDvate\u013E:
+jfx.gui.tsa.password=TSA heslo:
+jfx.gui.tsa.certFileType=Typ s\u00FAboru certifik\u00E1tu TSA:
+jfx.gui.tsa.certFile=S\u00FAbor certifik\u00E1tu TSA:
+jfx.gui.tsa.certPassword=Heslo certifik\u00E1tu TSA:
+jfx.gui.tsa.policyOid=OID politiky TSA:
+jfx.gui.tsa.hashAlgorithm=Hashovac\u00ED algoritmus TSA:
+jfx.gui.tsa.enableOcsp=Povoli\u0165 OCSP
+jfx.gui.tsa.ocspServerUrl=URL servera OCSP:
+jfx.gui.tsa.enableCrl=Povoli\u0165 CRL
+jfx.gui.tsa.proxyType=Typ proxy:
+jfx.gui.tsa.proxyHost=Proxy server:
+jfx.gui.tsa.proxyPort=Proxy port:
+jfx.gui.console.title=V\u00FDstupn\u00E1 konzola
+jfx.gui.console.clear=Vymaza\u0165
diff --git a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_ta.properties b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_ta.properties
index 93aa71d3..7549db3f 100644
--- a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_ta.properties
+++ b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_ta.properties
@@ -255,3 +255,103 @@ hlp.tsaAuthn=TSA \u0B9A\u0BC7\u0BB5\u0BC8\u0BAF\u0B95\u0BA4\u0BCD\u0BA4\u0BC8\u0
hlp.tsaCertFile=\u0B9A\u0BBE\u0BA9\u0BCD\u0BB1\u0BBF\u0BA4\u0BB4\u0BCD \u0B85\u0B99\u0BCD\u0B95\u0BC0\u0B95\u0BBE\u0BB0 \u0BAE\u0BC1\u0BB1\u0BC8 \u0BAA\u0BAF\u0BA9\u0BCD\u0BAA\u0B9F\u0BC1\u0BA4\u0BCD\u0BA4\u0BAA\u0BCD\u0BAA\u0B9F\u0BC1\u0BAE\u0BCD\u0BAA\u0BCB\u0BA4\u0BC1, \u0B9F\u0BBF\u0B8E\u0B9A\u0BCD\u0B8F \u0B9A\u0BC7\u0BB5\u0BC8\u0BAF\u0B95\u0BA4\u0BCD\u0BA4\u0BBF\u0BB1\u0BCD\u0B95\u0BC1 \u0B8E\u0BA4\u0BBF\u0BB0\u0BBE\u0BA9 \u0B85\u0B99\u0BCD\u0B95\u0BC0\u0B95\u0BBE\u0BB0\u0BA4\u0BCD\u0BA4\u0BBF\u0BB1\u0BCD\u0B95\u0BC1 \u0BAA\u0BAF\u0BA9\u0BCD\u0BAA\u0B9F\u0BC1\u0BA4\u0BCD\u0BA4\u0BAA\u0BCD\u0BAA\u0B9F\u0BC1\u0BAE\u0BCD \u0BA4\u0BA9\u0BBF\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F \u0BB5\u0BBF\u0B9A\u0BC8\u0BAF\u0BC8\u0B95\u0BCD \u0B95\u0BCA\u0BA3\u0BCD\u0B9F \u0B95\u0BC0\u0B9A\u0BCD\u0B9F\u0BCB\u0BB0\u0BCD \u0B95\u0BCB\u0BAA\u0BCD\u0BAA\u0BBF\u0BB1\u0BCD\u0B95\u0BBE\u0BA9 \u0BAA\u0BBE\u0BA4\u0BC8
hlp.tsaCertFileType=TSA \u0B9A\u0BBE\u0BA9\u0BCD\u0BB1\u0BBF\u0BA4\u0BB4\u0BCD \u0B85\u0B99\u0BCD\u0B95\u0BC0\u0B95\u0BBE\u0BB0\u0BA4\u0BCD\u0BA4\u0BBF\u0BB1\u0BCD\u0B95\u0BBE\u0BA9 \u0B95\u0BC0\u0B9A\u0BCD\u0B9F\u0BCB\u0BB0\u0BCD \u0BB5\u0B95\u0BC8 - \u0B87\u0BAF\u0BB2\u0BCD\u0BAA\u0BC1\u0BA8\u0BBF\u0BB2\u0BC8 PKCS12
hlp.tsaCertPasswd=\u0BA4\u0BA9\u0BBF\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F \u0BB5\u0BBF\u0B9A\u0BC8\u0BAF\u0BC1\u0B9F\u0BA9\u0BCD PKCS#12 \u0B95\u0BCB\u0BAA\u0BCD\u0BAA\u0BC8 (-TSCF \u0BB5\u0BBF\u0BB0\u0BC1\u0BAA\u0BCD\u0BAA\u0BA4\u0BCD\u0BA4\u0BC8\u0BAA\u0BCD \u0BAA\u0BBE\u0BB0\u0BCD\u0B95\u0BCD\u0B95\u0BB5\u0BC1\u0BAE\u0BCD) \u0BA4\u0BBF\u0BB1\u0B95\u0BCD\u0B95 \u0B95\u0B9F\u0BB5\u0BC1\u0B9A\u0BCD\u0B9A\u0BCA\u0BB2\u0BCD \u0BAA\u0BAF\u0BA9\u0BCD\u0BAA\u0B9F\u0BC1\u0BA4\u0BCD\u0BA4\u0BAA\u0BCD\u0BAA\u0B9F\u0BC1\u0B95\u0BBF\u0BB1\u0BA4\u0BC1
+#
+# JavaFX GUI
+#
+jfx.gui.menu.file=\u0B95\u0BCB\u0BAA\u0BCD\u0BAA\u0BC1
+jfx.gui.menu.file.open=PDF \u0BA4\u0BBF\u0BB1...
+jfx.gui.menu.file.close=\u0BAE\u0BC2\u0B9F\u0BC1
+jfx.gui.menu.file.sign=\u0B95\u0BC8\u0BAF\u0BCA\u0BAA\u0BCD\u0BAA\u0BAE\u0BBF\u0B9F\u0BC1
+jfx.gui.menu.file.recentFiles=\u0b87\u0ba4\u0bcd\u0ba4\u0bc0\u0baa\u0b9f\u0bcd\u0b9f \u0b95\u0bcb\u0baa\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bcd
+jfx.gui.menu.file.recentFiles.empty=\u0b87\u0ba4\u0bcd\u0ba4\u0bc0\u0baa\u0b9f\u0bcd\u0b9f \u0b95\u0bcb\u0baa\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bcd \u0b87\u0bb2\u0bcd\u0bb2\u0bc8
+jfx.gui.menu.file.exit=\u0BB5\u0BC6\u0BB3\u0BBF\u0BAF\u0BC7\u0BB1\u0BC1
+jfx.gui.menu.view=\u0B95\u0BBE\u0B9F\u0BCD\u0B9A\u0BBF
+jfx.gui.menu.view.zoomIn=\u0BAA\u0BC6\u0BB0\u0BBF\u0BA4\u0BBE\u0B95\u0BCD\u0B95\u0BC1
+jfx.gui.menu.view.zoomOut=\u0B9A\u0BBF\u0BB1\u0BBF\u0BA4\u0BBE\u0B95\u0BCD\u0B95\u0BC1
+jfx.gui.menu.view.fitPage=\u0BAA\u0B95\u0BCD\u0B95\u0BA4\u0BCD\u0BA4\u0BBF\u0BB1\u0BCD\u0B95\u0BC1 \u0BAA\u0BCA\u0BB0\u0BC1\u0BA4\u0BCD\u0BA4\u0BC1
+jfx.gui.menu.view.toggleSidePanel=\u0BAA\u0B95\u0BCD\u0B95 \u0BAA\u0BB2\u0B95\u0BA4\u0BCD\u0BA4\u0BC8 \u0BAE\u0BBE\u0BB1\u0BCD\u0BB1\u0BC1
+jfx.gui.menu.signing=\u0B95\u0BC8\u0BAF\u0BCA\u0BAA\u0BCD\u0BAA\u0BAE\u0BBF\u0B9F\u0BC1\u0BA4\u0BB2\u0BCD
+jfx.gui.menu.help=\u0B89\u0BA4\u0BB5\u0BBF
+jfx.gui.menu.help.about=JSignPdf \u0BAA\u0BB1\u0BCD\u0BB1\u0BBF
+jfx.gui.toolbar.open=\u0BA4\u0BBF\u0BB1
+jfx.gui.toolbar.fit=\u0BAA\u0BCA\u0BB0\u0BC1\u0BA4\u0BCD\u0BA4\u0BC1
+jfx.gui.toolbar.sign=\u0B95\u0BC8\u0BAF\u0BCA\u0BAA\u0BCD\u0BAA\u0BAE\u0BBF\u0B9F\u0BC1
+jfx.gui.panel.certificate=\u0B9A\u0BBE\u0BA9\u0BCD\u0BB1\u0BBF\u0BA4\u0BB4\u0BCD
+jfx.gui.panel.signatureAppearance=\u0B95\u0BC8\u0BAF\u0BCA\u0BAA\u0BCD\u0BAA\u0BAE\u0BCD \u0BA4\u0BCB\u0BB1\u0BCD\u0BB1\u0BAE\u0BCD
+jfx.gui.panel.timestampValidation=\u0BA8\u0BC7\u0BB0\u0BAE\u0BC1\u0BA4\u0BCD\u0BA4\u0BBF\u0BB0\u0BC8 & \u0B9A\u0BB0\u0BBF\u0BAA\u0BBE\u0BB0\u0BCD\u0BAA\u0BCD\u0BAA\u0BC1
+jfx.gui.panel.encryptionRights=\u0BAE\u0BB1\u0BC8\u0BAF\u0BBE\u0B95\u0BCD\u0B95\u0BAE\u0BCD & \u0B89\u0BB0\u0BBF\u0BAE\u0BC8\u0B95\u0BB3\u0BCD
+jfx.gui.dropHint=PDF \u0B95\u0BCB\u0BAA\u0BCD\u0BAA\u0BC8 \u0B87\u0B99\u0BCD\u0B95\u0BC7 \u0B87\u0BB4\u0BC1\u0B95\u0BCD\u0B95\u0BB5\u0BC1\u0BAE\u0BCD \u0B85\u0BB2\u0BCD\u0BB2\u0BA4\u0BC1 \u0B95\u0BCB\u0BAA\u0BCD\u0BAA\u0BC1 > \u0BA4\u0BBF\u0BB1 \u0BAA\u0BAF\u0BA9\u0BCD\u0BAA\u0B9F\u0BC1\u0BA4\u0BCD\u0BA4\u0BB5\u0BC1\u0BAE\u0BCD
+jfx.gui.status.ready=\u0BA4\u0BAF\u0BBE\u0BB0\u0BCD
+jfx.gui.status.signingInProgress=\u0B95\u0BC8\u0BAF\u0BCA\u0BAA\u0BCD\u0BAA\u0BAE\u0BBF\u0B9F\u0BC1\u0B95\u0BBF\u0BB1\u0BA4\u0BC1...
+jfx.gui.status.signingOk=\u0B95\u0BC8\u0BAF\u0BCA\u0BAA\u0BCD\u0BAA\u0BAE\u0BCD \u0BB5\u0BC6\u0BB1\u0BCD\u0BB1\u0BBF\u0B95\u0BB0\u0BAE\u0BBE\u0B95 \u0BAE\u0BC1\u0B9F\u0BBF\u0BA8\u0BCD\u0BA4\u0BA4\u0BC1
+jfx.gui.status.signingFailed=\u0B95\u0BC8\u0BAF\u0BCA\u0BAA\u0BCD\u0BAA\u0BAE\u0BCD \u0BA4\u0BCB\u0BB2\u0BCD\u0BB5\u0BBF\u0BAF\u0B9F\u0BC8\u0BA8\u0BCD\u0BA4\u0BA4\u0BC1
+jfx.gui.status.renderError=\u0BAA\u0B95\u0BCD\u0B95\u0BAE\u0BCD \u0B95\u0BBE\u0B9F\u0BCD\u0B9A\u0BBF\u0BAF\u0BBE\u0B95\u0BCD\u0B95\u0BA4\u0BCD\u0BA4\u0BBF\u0BB2\u0BCD \u0BAA\u0BBF\u0BB4\u0BC8
+jfx.gui.status.readError=\u0BAA\u0BBF\u0BB4\u0BC8: PDF \u0B95\u0BCB\u0BAA\u0BCD\u0BAA\u0BC8 \u0BAA\u0B9F\u0BBF\u0B95\u0BCD\u0B95 \u0BAE\u0BC1\u0B9F\u0BBF\u0BAF\u0BB5\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8
+jfx.gui.status.shiftToReplace=Shift \u0b85\u0bae\u0bc1\u0b95\u0bcd\u0b95\u0bbf \u0b95\u0bc8\u0baf\u0bc6\u0bb4\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1\u0baa\u0bcd \u0baa\u0b95\u0bc1\u0ba4\u0bbf\u0baf\u0bbf\u0bb2\u0bcd \u0b89\u0bb3\u0bcd\u0bb3 \u0b95\u0bc8\u0baf\u0bca\u0baa\u0bcd\u0baa \u0b9a\u0ba4\u0bc1\u0b95\u0ba4\u0bcd\u0ba4\u0bc8 \u0bae\u0bbe\u0bb1\u0bcd\u0bb1 \u0b87\u0bb4\u0bc1\u0b95\u0bcd\u0b95\u0bb5\u0bc1\u0bae\u0bcd
+jfx.gui.dialog.signingComplete.title=\u0B95\u0BC8\u0BAF\u0BCA\u0BAA\u0BCD\u0BAA\u0BAE\u0BCD \u0BAE\u0BC1\u0B9F\u0BBF\u0BA8\u0BCD\u0BA4\u0BA4\u0BC1
+jfx.gui.dialog.signingComplete.text=PDF \u0BB5\u0BC6\u0BB1\u0BCD\u0BB1\u0BBF\u0B95\u0BB0\u0BAE\u0BBE\u0B95 \u0B95\u0BC8\u0BAF\u0BCA\u0BAA\u0BCD\u0BAA\u0BAE\u0BBF\u0B9F\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1.
+jfx.gui.dialog.signingFailed.title=\u0B95\u0BC8\u0BAF\u0BCA\u0BAA\u0BCD\u0BAA\u0BAE\u0BCD \u0BA4\u0BCB\u0BB2\u0BCD\u0BB5\u0BBF\u0BAF\u0B9F\u0BC8\u0BA8\u0BCD\u0BA4\u0BA4\u0BC1
+jfx.gui.dialog.signingFailed.text=\u0B95\u0BC8\u0BAF\u0BCA\u0BAA\u0BCD\u0BAA\u0BAE\u0BBF\u0B9F\u0BC1\u0BA4\u0BB2\u0BCD \u0BA4\u0BCB\u0BB2\u0BCD\u0BB5\u0BBF\u0BAF\u0B9F\u0BC8\u0BA8\u0BCD\u0BA4\u0BA4\u0BC1. \u0BB5\u0BC6\u0BB3\u0BBF\u0BAF\u0BC0\u0B9F\u0BCD\u0B9F\u0BC1 \u0B95\u0BA9\u0BCD\u0B9A\u0BCB\u0BB2\u0BC8\u0BAA\u0BCD \u0BAA\u0BBE\u0BB0\u0BCD\u0B95\u0BCD\u0B95\u0BB5\u0BC1\u0BAE\u0BCD.
+jfx.gui.dialog.signingError.title=\u0B95\u0BC8\u0BAF\u0BCA\u0BAA\u0BCD\u0BAA\u0BAE\u0BBF\u0B9F\u0BC1\u0BA4\u0BB2\u0BCD \u0BAA\u0BBF\u0BB4\u0BC8
+jfx.gui.dialog.noDocument.title=\u0B86\u0BB5\u0BA3\u0BAE\u0BCD \u0B87\u0BB2\u0BCD\u0BB2\u0BC8
+jfx.gui.dialog.noDocument.text=\u0BAE\u0BC1\u0BA4\u0BB2\u0BBF\u0BB2\u0BCD PDF \u0B86\u0BB5\u0BA3\u0BA4\u0BCD\u0BA4\u0BC8\u0BA4\u0BCD \u0BA4\u0BBF\u0BB1\u0B95\u0BCD\u0B95\u0BB5\u0BC1\u0BAE\u0BCD.
+jfx.gui.dialog.openPdf.title=PDF \u0BA4\u0BBF\u0BB1
+jfx.gui.dialog.about.description=PDF \u0B95\u0BC8\u0BAF\u0BCA\u0BAA\u0BCD\u0BAA\u0BAE\u0BBF\u0B9F\u0BC1\u0BA4\u0BB2\u0BC1\u0B95\u0BCD\u0B95\u0BBE\u0BA9 \u0B89\u0BB0\u0BBF\u0BAE\u0BAE\u0BB1\u0BCD\u0BB1 \u0BAA\u0BAF\u0BA9\u0BCD\u0BAA\u0BBE\u0B9F\u0BC1.
+jfx.gui.dialog.selectKeystoreFile=Keystore \u0B95\u0BCB\u0BAA\u0BCD\u0BAA\u0BC8\u0BA4\u0BCD \u0BA4\u0BC7\u0BB0\u0BCD\u0BB5\u0BC1 \u0B9A\u0BC6\u0BAF\u0BCD\u0B95
+jfx.gui.dialog.selectSignatureImage=\u0B95\u0BC8\u0BAF\u0BCA\u0BAA\u0BCD\u0BAA\u0BAE\u0BCD \u0BAA\u0B9F\u0BA4\u0BCD\u0BA4\u0BC8\u0BA4\u0BCD \u0BA4\u0BC7\u0BB0\u0BCD\u0BB5\u0BC1 \u0B9A\u0BC6\u0BAF\u0BCD\u0B95
+jfx.gui.dialog.selectBackgroundImage=\u0BAA\u0BBF\u0BA9\u0BCD\u0BA9\u0BA3\u0BBF\u0BAA\u0BCD \u0BAA\u0B9F\u0BA4\u0BCD\u0BA4\u0BC8\u0BA4\u0BCD \u0BA4\u0BC7\u0BB0\u0BCD\u0BB5\u0BC1 \u0B9A\u0BC6\u0BAF\u0BCD\u0B95
+jfx.gui.dialog.selectOutputPdf=\u0BB5\u0BC6\u0BB3\u0BBF\u0BAF\u0BC0\u0B9F\u0BCD\u0B9F\u0BC1 PDF \u0B95\u0BCB\u0BAA\u0BCD\u0BAA\u0BC8\u0BA4\u0BCD \u0BA4\u0BC7\u0BB0\u0BCD\u0BB5\u0BC1 \u0B9A\u0BC6\u0BAF\u0BCD\u0B95
+jfx.gui.dialog.selectEncryptionCert=\u0BAE\u0BB1\u0BC8\u0BAF\u0BBE\u0B95\u0BCD\u0B95 \u0B9A\u0BBE\u0BA9\u0BCD\u0BB1\u0BBF\u0BA4\u0BB4\u0BC8\u0BA4\u0BCD \u0BA4\u0BC7\u0BB0\u0BCD\u0BB5\u0BC1 \u0B9A\u0BC6\u0BAF\u0BCD\u0B95
+jfx.gui.dialog.selectTsaCertFile=TSA \u0B9A\u0BBE\u0BA9\u0BCD\u0BB1\u0BBF\u0BA4\u0BB4\u0BCD \u0B95\u0BCB\u0BAA\u0BCD\u0BAA\u0BC8\u0BA4\u0BCD \u0BA4\u0BC7\u0BB0\u0BCD\u0BB5\u0BC1 \u0B9A\u0BC6\u0BAF\u0BCD\u0B95
+jfx.gui.cert.keystoreType=Keystore \u0BB5\u0B95\u0BC8:
+jfx.gui.cert.keystoreFile=Keystore \u0B95\u0BCB\u0BAA\u0BCD\u0BAA\u0BC1:
+jfx.gui.cert.keystorePassword=Keystore \u0B95\u0B9F\u0BB5\u0BC1\u0B9A\u0BCD\u0B9A\u0BCA\u0BB2\u0BCD:
+jfx.gui.cert.loadKeys=\u0BB5\u0BBF\u0B9A\u0BC8\u0B95\u0BB3\u0BC8 \u0B8F\u0BB1\u0BCD\u0BB1\u0BC1
+jfx.gui.cert.keyAlias=\u0BB5\u0BBF\u0B9A\u0BC8 \u0BAE\u0BBE\u0BB1\u0BCD\u0BB1\u0BC1\u0BAA\u0BCD\u0BAA\u0BC6\u0BAF\u0BB0\u0BCD:
+jfx.gui.cert.keyPassword=\u0BB5\u0BBF\u0B9A\u0BC8 \u0B95\u0B9F\u0BB5\u0BC1\u0B9A\u0BCD\u0B9A\u0BCA\u0BB2\u0BCD:
+jfx.gui.cert.storePasswords=\u0B95\u0B9F\u0BB5\u0BC1\u0B9A\u0BCD\u0B9A\u0BCA\u0BB1\u0BCD\u0B95\u0BB3\u0BC8\u0B9A\u0BCD \u0B9A\u0BC7\u0BAE\u0BBF
+jfx.gui.sig.enableVisible=\u0BAA\u0BC1\u0BB2\u0BAA\u0BCD\u0BAA\u0B9F\u0BC1\u0BAE\u0BCD \u0B95\u0BC8\u0BAF\u0BCA\u0BAA\u0BCD\u0BAA\u0BA4\u0BCD\u0BA4\u0BC8 \u0B9A\u0BC6\u0BAF\u0BB2\u0BCD\u0BAA\u0B9F\u0BC1\u0BA4\u0BCD\u0BA4\u0BC1
+jfx.gui.sig.renderMode=\u0BAA\u0BAF\u0BA9\u0BCD\u0BAE\u0BC1\u0BB1\u0BC8:
+jfx.gui.sig.l2Text=\u0B95\u0BC8\u0BAF\u0BCA\u0BAA\u0BCD\u0BAA\u0BAE\u0BCD \u0B89\u0BB0\u0BC8:
+jfx.gui.sig.l4Text=\u0BA8\u0BBF\u0BB2\u0BC8 \u0B89\u0BB0\u0BC8:
+jfx.gui.sig.fontSize=\u0B8E\u0BB4\u0BC1\u0BA4\u0BCD\u0BA4\u0BC1\u0BB0\u0BC1 \u0B85\u0BB3\u0BB5\u0BC1:
+jfx.gui.sig.signatureImage=\u0B95\u0BC8\u0BAF\u0BCA\u0BAA\u0BCD\u0BAA\u0BAE\u0BCD \u0BAA\u0B9F\u0BAE\u0BCD:
+jfx.gui.sig.backgroundImage=\u0BAA\u0BBF\u0BA9\u0BCD\u0BA9\u0BA3\u0BBF\u0BAA\u0BCD \u0BAA\u0B9F\u0BAE\u0BCD:
+jfx.gui.sig.acro6Layers=Acrobat 6 layer mode
+jfx.gui.sig.hashAlgorithm=Hash \u0B85\u0BB2\u0BCD\u0B95\u0BBE\u0BB0\u0BBF\u0BA4\u0BAE\u0BCD:
+jfx.gui.sig.certLevel=\u0B9A\u0BBE\u0BA9\u0BCD\u0BB1\u0BBF\u0BA4\u0BB4\u0BCD \u0BA8\u0BBF\u0BB2\u0BC8:
+jfx.gui.sig.signerName=\u0B95\u0BC8\u0BAF\u0BCA\u0BAA\u0BCD\u0BAA\u0BAE\u0BBF\u0B9F\u0BCD\u0B9F\u0BB5\u0BB0\u0BCD \u0BAA\u0BC6\u0BAF\u0BB0\u0BCD:
+jfx.gui.sig.reason=\u0B95\u0BBE\u0BB0\u0BA3\u0BAE\u0BCD:
+jfx.gui.sig.location=\u0B87\u0B9F\u0BAE\u0BCD:
+jfx.gui.sig.contact=\u0BA4\u0BCA\u0B9F\u0BB0\u0BCD\u0BAA\u0BC1:
+jfx.gui.sig.appendSignature=\u0B95\u0BC8\u0BAF\u0BCA\u0BAA\u0BCD\u0BAA\u0BA4\u0BCD\u0BA4\u0BC8 \u0B9A\u0BC7\u0BB0\u0BCD
+jfx.gui.sig.outputFile=\u0BB5\u0BC6\u0BB3\u0BBF\u0BAF\u0BC0\u0B9F\u0BCD\u0B9F\u0BC1 \u0B95\u0BCB\u0BAA\u0BCD\u0BAA\u0BC1:
+jfx.gui.enc.pdfEncryption=PDF \u0BAE\u0BB1\u0BC8\u0BAF\u0BBE\u0B95\u0BCD\u0B95\u0BAE\u0BCD:
+jfx.gui.enc.ownerPassword=\u0B89\u0BB0\u0BBF\u0BAE\u0BC8\u0BAF\u0BBE\u0BB3\u0BB0\u0BCD \u0B95\u0B9F\u0BB5\u0BC1\u0B9A\u0BCD\u0B9A\u0BCA\u0BB2\u0BCD:
+jfx.gui.enc.userPassword=\u0BAA\u0BAF\u0BA9\u0BB0\u0BCD \u0B95\u0B9F\u0BB5\u0BC1\u0B9A\u0BCD\u0B9A\u0BCA\u0BB2\u0BCD:
+jfx.gui.enc.encryptionCert=\u0BAE\u0BB1\u0BC8\u0BAF\u0BBE\u0B95\u0BCD\u0B95 \u0B9A\u0BBE\u0BA9\u0BCD\u0BB1\u0BBF\u0BA4\u0BB4\u0BCD:
+jfx.gui.enc.printRight=\u0B85\u0B9A\u0BCD\u0B9A\u0BBF\u0B9F\u0BC1 \u0B89\u0BB0\u0BBF\u0BAE\u0BC8:
+jfx.gui.enc.allowCopy=\u0BAA\u0B9F\u0BBF\u0BAF\u0BC6\u0B9F\u0BC1\u0B95\u0BCD\u0B95 \u0B85\u0BA9\u0BC1\u0BAE\u0BA4\u0BBF
+jfx.gui.enc.allowAssembly=\u0BA4\u0BCA\u0B95\u0BC1\u0B95\u0BCD\u0B95 \u0B85\u0BA9\u0BC1\u0BAE\u0BA4\u0BBF
+jfx.gui.enc.allowFillIn=\u0BA8\u0BBF\u0BB0\u0BAA\u0BCD\u0BAA \u0B85\u0BA9\u0BC1\u0BAE\u0BA4\u0BBF
+jfx.gui.enc.allowScreenReaders=\u0BA4\u0BBF\u0BB0\u0BC8 \u0BAA\u0B9F\u0BBF\u0BAA\u0BCD\u0BAA\u0BBE\u0BA9\u0BCD\u0B95\u0BB3\u0BCD \u0B85\u0BA9\u0BC1\u0BAE\u0BA4\u0BBF
+jfx.gui.enc.allowModifyAnnotations=\u0B95\u0BC1\u0BB1\u0BBF\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BC8 \u0BAE\u0BBE\u0BB1\u0BCD\u0BB1 \u0B85\u0BA9\u0BC1\u0BAE\u0BA4\u0BBF
+jfx.gui.enc.allowModifyContents=\u0B89\u0BB3\u0BCD\u0BB3\u0B9F\u0B95\u0BCD\u0B95\u0BA4\u0BCD\u0BA4\u0BC8 \u0BAE\u0BBE\u0BB1\u0BCD\u0BB1 \u0B85\u0BA9\u0BC1\u0BAE\u0BA4\u0BBF
+jfx.gui.tsa.enableTimestamp=\u0BA8\u0BC7\u0BB0\u0BAE\u0BC1\u0BA4\u0BCD\u0BA4\u0BBF\u0BB0\u0BC8\u0BAF\u0BC8 \u0B9A\u0BC6\u0BAF\u0BB2\u0BCD\u0BAA\u0B9F\u0BC1\u0BA4\u0BCD\u0BA4\u0BC1 (TSA)
+jfx.gui.tsa.serverUrl=TSA \u0B9A\u0BC7\u0BB5\u0BC8\u0BAF\u0B95 URL:
+jfx.gui.tsa.authentication=\u0B85\u0B99\u0BCD\u0B95\u0BC0\u0B95\u0BBE\u0BB0\u0BAE\u0BCD:
+jfx.gui.tsa.user=TSA \u0BAA\u0BAF\u0BA9\u0BB0\u0BCD:
+jfx.gui.tsa.password=TSA \u0B95\u0B9F\u0BB5\u0BC1\u0B9A\u0BCD\u0B9A\u0BCA\u0BB2\u0BCD:
+jfx.gui.tsa.certFileType=TSA \u0B9A\u0BBE\u0BA9\u0BCD\u0BB1\u0BBF\u0BA4\u0BB4\u0BCD \u0B95\u0BCB\u0BAA\u0BCD\u0BAA\u0BC1 \u0BB5\u0B95\u0BC8:
+jfx.gui.tsa.certFile=TSA \u0B9A\u0BBE\u0BA9\u0BCD\u0BB1\u0BBF\u0BA4\u0BB4\u0BCD \u0B95\u0BCB\u0BAA\u0BCD\u0BAA\u0BC1:
+jfx.gui.tsa.certPassword=TSA \u0B9A\u0BBE\u0BA9\u0BCD\u0BB1\u0BBF\u0BA4\u0BB4\u0BCD \u0B95\u0B9F\u0BB5\u0BC1\u0B9A\u0BCD\u0B9A\u0BCA\u0BB2\u0BCD:
+jfx.gui.tsa.policyOid=TSA \u0B95\u0BCA\u0BB3\u0BCD\u0B95\u0BC8 OID:
+jfx.gui.tsa.hashAlgorithm=TSA hash \u0B85\u0BB2\u0BCD\u0B95\u0BBE\u0BB0\u0BBF\u0BA4\u0BAE\u0BCD:
+jfx.gui.tsa.enableOcsp=OCSP \u0B9A\u0BC6\u0BAF\u0BB2\u0BCD\u0BAA\u0B9F\u0BC1\u0BA4\u0BCD\u0BA4\u0BC1
+jfx.gui.tsa.ocspServerUrl=OCSP \u0B9A\u0BC7\u0BB5\u0BC8\u0BAF\u0B95 URL:
+jfx.gui.tsa.enableCrl=CRL \u0B9A\u0BC6\u0BAF\u0BB2\u0BCD\u0BAA\u0B9F\u0BC1\u0BA4\u0BCD\u0BA4\u0BC1
+jfx.gui.tsa.proxyType=Proxy \u0BB5\u0B95\u0BC8:
+jfx.gui.tsa.proxyHost=Proxy \u0BB5\u0BB4\u0B99\u0BCD\u0B95\u0BA9\u0BCD:
+jfx.gui.tsa.proxyPort=Proxy \u0BA4\u0BC1\u0BB1\u0BC8\u0BAE\u0BC1\u0B95\u0BAE\u0BCD:
+jfx.gui.console.title=\u0BB5\u0BC6\u0BB3\u0BBF\u0BAF\u0BC0\u0B9F\u0BCD\u0B9F\u0BC1 \u0B95\u0BA9\u0BCD\u0B9A\u0BCB\u0BB2\u0BCD
+jfx.gui.console.clear=\u0B85\u0BB4\u0BBF
diff --git a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_zh_CN.properties b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_zh_CN.properties
index 609e32ad..edfb0244 100644
--- a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_zh_CN.properties
+++ b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_zh_CN.properties
@@ -255,3 +255,103 @@ serverAuthn.certificate=\u5BA2\u6237\u7AEF\u8BC1\u4E66
serverAuthn.none=\u65E0\u8BA4\u8BC1
serverAuthn.password=\u7528\u6237\u540D / \u5BC6\u7801
ssl.keymanager.init=\u6B63\u5728\u4ECE\u5BC6\u94A5\u5E93\u6587\u4EF6 {0} \u521D\u59CB\u5316\u5BC6\u94A5\u7BA1\u7406\u5668\u3002
+#
+# JavaFX GUI
+#
+jfx.gui.menu.file=\u6587\u4ef6
+jfx.gui.menu.file.open=\u6253\u5f00 PDF...
+jfx.gui.menu.file.close=\u5173\u95ed
+jfx.gui.menu.file.sign=\u7b7e\u540d
+jfx.gui.menu.file.recentFiles=\u6700\u8fd1\u6587\u4ef6
+jfx.gui.menu.file.recentFiles.empty=\u6ca1\u6709\u6700\u8fd1\u6587\u4ef6
+jfx.gui.menu.file.exit=\u9000\u51fa
+jfx.gui.menu.view=\u89c6\u56fe
+jfx.gui.menu.view.zoomIn=\u653e\u5927
+jfx.gui.menu.view.zoomOut=\u7f29\u5c0f
+jfx.gui.menu.view.fitPage=\u9002\u5408\u9875\u9762
+jfx.gui.menu.view.toggleSidePanel=\u5207\u6362\u4fa7\u8fb9\u680f
+jfx.gui.menu.signing=\u7b7e\u540d
+jfx.gui.menu.help=\u5e2e\u52a9
+jfx.gui.menu.help.about=\u5173\u4e8e JSignPdf
+jfx.gui.toolbar.open=\u6253\u5f00
+jfx.gui.toolbar.fit=\u9002\u5408
+jfx.gui.toolbar.sign=\u7b7e\u540d
+jfx.gui.panel.certificate=\u8bc1\u4e66
+jfx.gui.panel.signatureAppearance=\u7b7e\u540d\u5916\u89c2
+jfx.gui.panel.timestampValidation=\u65f6\u95f4\u6233\u548c\u9a8c\u8bc1
+jfx.gui.panel.encryptionRights=\u52a0\u5bc6\u548c\u6743\u9650
+jfx.gui.dropHint=\u5c06 PDF \u6587\u4ef6\u62d6\u653e\u5230\u6b64\u5904\u6216\u4f7f\u7528 \u6587\u4ef6 > \u6253\u5f00
+jfx.gui.status.ready=\u5c31\u7eea
+jfx.gui.status.signingInProgress=\u7b7e\u540d\u4e2d...
+jfx.gui.status.signingOk=\u7b7e\u540d\u6210\u529f\u5b8c\u6210
+jfx.gui.status.signingFailed=\u7b7e\u540d\u5931\u8d25
+jfx.gui.status.renderError=\u9875\u9762\u6e32\u67d3\u9519\u8bef
+jfx.gui.status.readError=\u9519\u8bef\uff1a\u65e0\u6cd5\u8bfb\u53d6 PDF \u6587\u4ef6
+jfx.gui.status.shiftToReplace=\u6309\u4f4f Shift \u5e76\u62d6\u52a8\u4ee5\u66ff\u6362\u7b7e\u540d\u77e9\u5f62
+jfx.gui.dialog.signingComplete.title=\u7b7e\u540d\u5b8c\u6210
+jfx.gui.dialog.signingComplete.text=PDF \u5df2\u6210\u529f\u7b7e\u540d\u3002
+jfx.gui.dialog.signingFailed.title=\u7b7e\u540d\u5931\u8d25
+jfx.gui.dialog.signingFailed.text=\u7b7e\u540d\u8fc7\u7a0b\u5931\u8d25\u3002\u8bf7\u67e5\u770b\u8f93\u51fa\u63a7\u5236\u53f0\u4e86\u89e3\u8be6\u60c5\u3002
+jfx.gui.dialog.signingError.title=\u7b7e\u540d\u9519\u8bef
+jfx.gui.dialog.noDocument.title=\u65e0\u6587\u6863
+jfx.gui.dialog.noDocument.text=\u8bf7\u5148\u6253\u5f00\u4e00\u4e2a PDF \u6587\u6863\u3002
+jfx.gui.dialog.openPdf.title=\u6253\u5f00 PDF
+jfx.gui.dialog.about.description=\u514d\u8d39\u7684 PDF \u7b7e\u540d\u5e94\u7528\u7a0b\u5e8f\u3002
+jfx.gui.dialog.selectKeystoreFile=\u9009\u62e9\u5bc6\u94a5\u5e93\u6587\u4ef6
+jfx.gui.dialog.selectSignatureImage=\u9009\u62e9\u7b7e\u540d\u56fe\u50cf
+jfx.gui.dialog.selectBackgroundImage=\u9009\u62e9\u80cc\u666f\u56fe\u50cf
+jfx.gui.dialog.selectOutputPdf=\u9009\u62e9\u8f93\u51fa PDF \u6587\u4ef6
+jfx.gui.dialog.selectEncryptionCert=\u9009\u62e9\u52a0\u5bc6\u8bc1\u4e66
+jfx.gui.dialog.selectTsaCertFile=\u9009\u62e9 TSA \u8bc1\u4e66\u6587\u4ef6
+jfx.gui.cert.keystoreType=\u5bc6\u94a5\u5e93\u7c7b\u578b\uff1a
+jfx.gui.cert.keystoreFile=\u5bc6\u94a5\u5e93\u6587\u4ef6\uff1a
+jfx.gui.cert.keystorePassword=\u5bc6\u94a5\u5e93\u5bc6\u7801\uff1a
+jfx.gui.cert.loadKeys=\u52a0\u8f7d\u5bc6\u94a5
+jfx.gui.cert.keyAlias=\u5bc6\u94a5\u522b\u540d\uff1a
+jfx.gui.cert.keyPassword=\u5bc6\u94a5\u5bc6\u7801\uff1a
+jfx.gui.cert.storePasswords=\u4fdd\u5b58\u5bc6\u7801
+jfx.gui.sig.enableVisible=\u542f\u7528\u53ef\u89c1\u7b7e\u540d
+jfx.gui.sig.renderMode=\u6e32\u67d3\u6a21\u5f0f\uff1a
+jfx.gui.sig.l2Text=\u7b7e\u540d\u6587\u672c\uff1a
+jfx.gui.sig.l4Text=\u72b6\u6001\u6587\u672c\uff1a
+jfx.gui.sig.fontSize=\u5b57\u4f53\u5927\u5c0f\uff1a
+jfx.gui.sig.signatureImage=\u7b7e\u540d\u56fe\u50cf\uff1a
+jfx.gui.sig.backgroundImage=\u80cc\u666f\u56fe\u50cf\uff1a
+jfx.gui.sig.acro6Layers=Acrobat 6 \u56fe\u5c42\u6a21\u5f0f
+jfx.gui.sig.hashAlgorithm=\u54c8\u5e0c\u7b97\u6cd5\uff1a
+jfx.gui.sig.certLevel=\u8ba4\u8bc1\u7ea7\u522b\uff1a
+jfx.gui.sig.signerName=\u7b7e\u540d\u8005\u540d\u79f0\uff1a
+jfx.gui.sig.reason=\u539f\u56e0\uff1a
+jfx.gui.sig.location=\u4f4d\u7f6e\uff1a
+jfx.gui.sig.contact=\u8054\u7cfb\u4eba\uff1a
+jfx.gui.sig.appendSignature=\u8ffd\u52a0\u7b7e\u540d
+jfx.gui.sig.outputFile=\u8f93\u51fa\u6587\u4ef6\uff1a
+jfx.gui.enc.pdfEncryption=PDF \u52a0\u5bc6\uff1a
+jfx.gui.enc.ownerPassword=\u6240\u6709\u8005\u5bc6\u7801\uff1a
+jfx.gui.enc.userPassword=\u7528\u6237\u5bc6\u7801\uff1a
+jfx.gui.enc.encryptionCert=\u52a0\u5bc6\u8bc1\u4e66\uff1a
+jfx.gui.enc.printRight=\u6253\u5370\u6743\u9650\uff1a
+jfx.gui.enc.allowCopy=\u5141\u8bb8\u590d\u5236
+jfx.gui.enc.allowAssembly=\u5141\u8bb8\u7ec4\u88c5
+jfx.gui.enc.allowFillIn=\u5141\u8bb8\u586b\u5199
+jfx.gui.enc.allowScreenReaders=\u5141\u8bb8\u5c4f\u5e55\u9605\u8bfb\u5668
+jfx.gui.enc.allowModifyAnnotations=\u5141\u8bb8\u4fee\u6539\u6ce8\u91ca
+jfx.gui.enc.allowModifyContents=\u5141\u8bb8\u4fee\u6539\u5185\u5bb9
+jfx.gui.tsa.enableTimestamp=\u542f\u7528\u65f6\u95f4\u6233 (TSA)
+jfx.gui.tsa.serverUrl=TSA \u670d\u52a1\u5668 URL\uff1a
+jfx.gui.tsa.authentication=\u8ba4\u8bc1\uff1a
+jfx.gui.tsa.user=TSA \u7528\u6237\uff1a
+jfx.gui.tsa.password=TSA \u5bc6\u7801\uff1a
+jfx.gui.tsa.certFileType=TSA \u8bc1\u4e66\u6587\u4ef6\u7c7b\u578b\uff1a
+jfx.gui.tsa.certFile=TSA \u8bc1\u4e66\u6587\u4ef6\uff1a
+jfx.gui.tsa.certPassword=TSA \u8bc1\u4e66\u5bc6\u7801\uff1a
+jfx.gui.tsa.policyOid=TSA \u7b56\u7565 OID\uff1a
+jfx.gui.tsa.hashAlgorithm=TSA \u54c8\u5e0c\u7b97\u6cd5\uff1a
+jfx.gui.tsa.enableOcsp=\u542f\u7528 OCSP
+jfx.gui.tsa.ocspServerUrl=OCSP \u670d\u52a1\u5668 URL\uff1a
+jfx.gui.tsa.enableCrl=\u542f\u7528 CRL
+jfx.gui.tsa.proxyType=\u4ee3\u7406\u7c7b\u578b\uff1a
+jfx.gui.tsa.proxyHost=\u4ee3\u7406\u4e3b\u673a\uff1a
+jfx.gui.tsa.proxyPort=\u4ee3\u7406\u7aef\u53e3\uff1a
+jfx.gui.console.title=\u8f93\u51fa\u63a7\u5236\u53f0
+jfx.gui.console.clear=\u6e05\u9664
diff --git a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_zh_TW.properties b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_zh_TW.properties
index 455563af..7e8bc3f5 100644
--- a/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_zh_TW.properties
+++ b/jsignpdf/src/main/resources/net/sf/jsignpdf/translations/messages_zh_TW.properties
@@ -255,3 +255,103 @@ serverAuthn.certificate=\u5BA2\u6236\u7AEF\u6191\u8B49
serverAuthn.none=\u7121\u8A8D\u8B49
serverAuthn.password=\u4F7F\u7528\u8005\u540D\u7A31 / \u5BC6\u78BC
ssl.keymanager.init=\u5F9Ekeystore\u6A94\u6848{0}\u521D\u59CB\u5316\u91D1\u9470\u7BA1\u7406\u7A0B\u5E8F\u3002
+#
+# JavaFX GUI
+#
+jfx.gui.menu.file=\u6a94\u6848
+jfx.gui.menu.file.open=\u958b\u555f PDF...
+jfx.gui.menu.file.close=\u95dc\u9589
+jfx.gui.menu.file.sign=\u7c3d\u7f72
+jfx.gui.menu.file.recentFiles=\u6700\u8fd1\u6a94\u6848
+jfx.gui.menu.file.recentFiles.empty=\u6c92\u6709\u6700\u8fd1\u6a94\u6848
+jfx.gui.menu.file.exit=\u7d50\u675f
+jfx.gui.menu.view=\u6aa2\u8996
+jfx.gui.menu.view.zoomIn=\u653e\u5927
+jfx.gui.menu.view.zoomOut=\u7e2e\u5c0f
+jfx.gui.menu.view.fitPage=\u9069\u5408\u9801\u9762
+jfx.gui.menu.view.toggleSidePanel=\u5207\u63db\u5074\u908a\u6b04
+jfx.gui.menu.signing=\u7c3d\u7f72
+jfx.gui.menu.help=\u8aaa\u660e
+jfx.gui.menu.help.about=\u95dc\u65bc JSignPdf
+jfx.gui.toolbar.open=\u958b\u555f
+jfx.gui.toolbar.fit=\u9069\u5408
+jfx.gui.toolbar.sign=\u7c3d\u7f72
+jfx.gui.panel.certificate=\u6191\u8b49
+jfx.gui.panel.signatureAppearance=\u7c3d\u7ae0\u5916\u89c0
+jfx.gui.panel.timestampValidation=\u6642\u9593\u6233\u8207\u9a57\u8b49
+jfx.gui.panel.encryptionRights=\u52a0\u5bc6\u8207\u6b0a\u9650
+jfx.gui.dropHint=\u5c07 PDF \u6a94\u6848\u62d6\u653e\u81f3\u6b64\u8655\u6216\u4f7f\u7528 \u6a94\u6848 > \u958b\u555f
+jfx.gui.status.ready=\u5c31\u7dd2
+jfx.gui.status.signingInProgress=\u7c3d\u7f72\u4e2d...
+jfx.gui.status.signingOk=\u7c3d\u7f72\u6210\u529f\u5b8c\u6210
+jfx.gui.status.signingFailed=\u7c3d\u7f72\u5931\u6557
+jfx.gui.status.renderError=\u9801\u9762\u6e32\u67d3\u932f\u8aa4
+jfx.gui.status.readError=\u932f\u8aa4\uff1a\u7121\u6cd5\u8b80\u53d6 PDF \u6a94\u6848
+jfx.gui.status.shiftToReplace=\u6309\u4f4f Shift \u4e26\u62d6\u66f3\u4ee5\u66ff\u63db\u7c3d\u540d\u77e9\u5f62
+jfx.gui.dialog.signingComplete.title=\u7c3d\u7f72\u5b8c\u6210
+jfx.gui.dialog.signingComplete.text=PDF \u5df2\u6210\u529f\u7c3d\u7f72\u3002
+jfx.gui.dialog.signingFailed.title=\u7c3d\u7f72\u5931\u6557
+jfx.gui.dialog.signingFailed.text=\u7c3d\u7f72\u904e\u7a0b\u5931\u6557\u3002\u8acb\u6aa2\u67e5\u8f38\u51fa\u4e3b\u63a7\u53f0\u4e86\u89e3\u8a73\u60c5\u3002
+jfx.gui.dialog.signingError.title=\u7c3d\u7f72\u932f\u8aa4
+jfx.gui.dialog.noDocument.title=\u7121\u6587\u4ef6
+jfx.gui.dialog.noDocument.text=\u8acb\u5148\u958b\u555f\u4e00\u500b PDF \u6587\u4ef6\u3002
+jfx.gui.dialog.openPdf.title=\u958b\u555f PDF
+jfx.gui.dialog.about.description=\u514d\u8cbb\u7684 PDF \u7c3d\u7f72\u61c9\u7528\u7a0b\u5f0f\u3002
+jfx.gui.dialog.selectKeystoreFile=\u9078\u64c7\u5bc6\u9470\u5eab\u6a94\u6848
+jfx.gui.dialog.selectSignatureImage=\u9078\u64c7\u7c3d\u7ae0\u5f71\u50cf
+jfx.gui.dialog.selectBackgroundImage=\u9078\u64c7\u80cc\u666f\u5f71\u50cf
+jfx.gui.dialog.selectOutputPdf=\u9078\u64c7\u8f38\u51fa PDF \u6a94\u6848
+jfx.gui.dialog.selectEncryptionCert=\u9078\u64c7\u52a0\u5bc6\u6191\u8b49
+jfx.gui.dialog.selectTsaCertFile=\u9078\u64c7 TSA \u6191\u8b49\u6a94\u6848
+jfx.gui.cert.keystoreType=\u5bc6\u9470\u5eab\u985e\u578b\uff1a
+jfx.gui.cert.keystoreFile=\u5bc6\u9470\u5eab\u6a94\u6848\uff1a
+jfx.gui.cert.keystorePassword=\u5bc6\u9470\u5eab\u5bc6\u78bc\uff1a
+jfx.gui.cert.loadKeys=\u8f09\u5165\u91d1\u9470
+jfx.gui.cert.keyAlias=\u91d1\u9470\u5225\u540d\uff1a
+jfx.gui.cert.keyPassword=\u91d1\u9470\u5bc6\u78bc\uff1a
+jfx.gui.cert.storePasswords=\u5132\u5b58\u5bc6\u78bc
+jfx.gui.sig.enableVisible=\u555f\u7528\u53ef\u898b\u7c3d\u7ae0
+jfx.gui.sig.renderMode=\u6e32\u67d3\u6a21\u5f0f\uff1a
+jfx.gui.sig.l2Text=\u7c3d\u7ae0\u6587\u5b57\uff1a
+jfx.gui.sig.l4Text=\u72c0\u614b\u6587\u5b57\uff1a
+jfx.gui.sig.fontSize=\u5b57\u9ad4\u5927\u5c0f\uff1a
+jfx.gui.sig.signatureImage=\u7c3d\u7ae0\u5f71\u50cf\uff1a
+jfx.gui.sig.backgroundImage=\u80cc\u666f\u5f71\u50cf\uff1a
+jfx.gui.sig.acro6Layers=Acrobat 6 \u5716\u5c64\u6a21\u5f0f
+jfx.gui.sig.hashAlgorithm=\u96dc\u6e4a\u6f14\u7b97\u6cd5\uff1a
+jfx.gui.sig.certLevel=\u8a8d\u8b49\u5c64\u7d1a\uff1a
+jfx.gui.sig.signerName=\u7c3d\u7f72\u8005\u540d\u7a31\uff1a
+jfx.gui.sig.reason=\u539f\u56e0\uff1a
+jfx.gui.sig.location=\u5730\u9ede\uff1a
+jfx.gui.sig.contact=\u806f\u7d61\u4eba\uff1a
+jfx.gui.sig.appendSignature=\u9644\u52a0\u7c3d\u7ae0
+jfx.gui.sig.outputFile=\u8f38\u51fa\u6a94\u6848\uff1a
+jfx.gui.enc.pdfEncryption=PDF \u52a0\u5bc6\uff1a
+jfx.gui.enc.ownerPassword=\u64c1\u6709\u8005\u5bc6\u78bc\uff1a
+jfx.gui.enc.userPassword=\u4f7f\u7528\u8005\u5bc6\u78bc\uff1a
+jfx.gui.enc.encryptionCert=\u52a0\u5bc6\u6191\u8b49\uff1a
+jfx.gui.enc.printRight=\u5217\u5370\u6b0a\u9650\uff1a
+jfx.gui.enc.allowCopy=\u5141\u8a31\u8907\u88fd
+jfx.gui.enc.allowAssembly=\u5141\u8a31\u7d44\u5408
+jfx.gui.enc.allowFillIn=\u5141\u8a31\u586b\u5beb
+jfx.gui.enc.allowScreenReaders=\u5141\u8a31\u87a2\u5e55\u9605\u8b80\u5668
+jfx.gui.enc.allowModifyAnnotations=\u5141\u8a31\u4fee\u6539\u8a3b\u91cb
+jfx.gui.enc.allowModifyContents=\u5141\u8a31\u4fee\u6539\u5167\u5bb9
+jfx.gui.tsa.enableTimestamp=\u555f\u7528\u6642\u9593\u6233 (TSA)
+jfx.gui.tsa.serverUrl=TSA \u4f3a\u670d\u5668 URL\uff1a
+jfx.gui.tsa.authentication=\u8a8d\u8b49\uff1a
+jfx.gui.tsa.user=TSA \u4f7f\u7528\u8005\uff1a
+jfx.gui.tsa.password=TSA \u5bc6\u78bc\uff1a
+jfx.gui.tsa.certFileType=TSA \u6191\u8b49\u6a94\u6848\u985e\u578b\uff1a
+jfx.gui.tsa.certFile=TSA \u6191\u8b49\u6a94\u6848\uff1a
+jfx.gui.tsa.certPassword=TSA \u6191\u8b49\u5bc6\u78bc\uff1a
+jfx.gui.tsa.policyOid=TSA \u653f\u7b56 OID\uff1a
+jfx.gui.tsa.hashAlgorithm=TSA \u96dc\u6e4a\u6f14\u7b97\u6cd5\uff1a
+jfx.gui.tsa.enableOcsp=\u555f\u7528 OCSP
+jfx.gui.tsa.ocspServerUrl=OCSP \u4f3a\u670d\u5668 URL\uff1a
+jfx.gui.tsa.enableCrl=\u555f\u7528 CRL
+jfx.gui.tsa.proxyType=\u4ee3\u7406\u985e\u578b\uff1a
+jfx.gui.tsa.proxyHost=\u4ee3\u7406\u4e3b\u6a5f\uff1a
+jfx.gui.tsa.proxyPort=\u4ee3\u7406\u9023\u63a5\u57e0\uff1a
+jfx.gui.console.title=\u8f38\u51fa\u4e3b\u63a7\u53f0
+jfx.gui.console.clear=\u6e05\u9664
diff --git a/jsignpdf/src/test/java/net/sf/jsignpdf/BasicSignerOptionsTest.java b/jsignpdf/src/test/java/net/sf/jsignpdf/BasicSignerOptionsTest.java
new file mode 100644
index 00000000..efb9c4e9
--- /dev/null
+++ b/jsignpdf/src/test/java/net/sf/jsignpdf/BasicSignerOptionsTest.java
@@ -0,0 +1,200 @@
+package net.sf.jsignpdf;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+
+import java.net.Proxy;
+
+import net.sf.jsignpdf.types.CertificationLevel;
+import net.sf.jsignpdf.types.HashAlgorithm;
+import net.sf.jsignpdf.types.PDFEncryption;
+import net.sf.jsignpdf.types.PrintRight;
+import net.sf.jsignpdf.types.RenderMode;
+import net.sf.jsignpdf.types.ServerAuthentication;
+import org.junit.Test;
+
+/**
+ * Tests for {@link BasicSignerOptions#createCopy()}.
+ */
+public class BasicSignerOptionsTest {
+
+ @Test
+ public void createCopyShouldProduceEqualInstance() {
+ BasicSignerOptions original = new BasicSignerOptions();
+
+ // String fields
+ original.setKsType("PKCS12");
+ original.setKsFile("/path/to/keystore");
+ original.setKsPasswd("ksPass".toCharArray());
+ original.setKeyAlias("myAlias");
+ original.setKeyIndex(3);
+ original.setKeyPasswd("keyPass".toCharArray());
+ original.setInFile("/input.pdf");
+ original.setOutFile("/output.pdf");
+ original.setSignerName("Test Signer");
+ original.setReason("Testing");
+ original.setLocation("Prague");
+ original.setContact("test@example.com");
+ original.setAppend(true);
+ original.setAdvanced(true);
+
+ // Encryption
+ original.setPdfEncryption(PDFEncryption.PASSWORD);
+ original.setPdfOwnerPwd("ownerPwd".toCharArray());
+ original.setPdfUserPwd("userPwd".toCharArray());
+ original.setPdfEncryptionCertFile("/cert.pem");
+ original.setCertLevel(CertificationLevel.CERTIFIED_NO_CHANGES_ALLOWED);
+ original.setHashAlgorithm(HashAlgorithm.SHA256);
+ original.setStorePasswords(true);
+
+ // Rights
+ original.setRightPrinting(PrintRight.ALLOW_DEGRADED_PRINTING);
+ original.setRightCopy(true);
+ original.setRightAssembly(true);
+ original.setRightFillIn(true);
+ original.setRightScreanReaders(true);
+ original.setRightModifyAnnotations(true);
+ original.setRightModifyContents(true);
+
+ // Visible signature
+ original.setVisible(true);
+ original.setPage(5);
+ original.setPositionLLX(10.0f);
+ original.setPositionLLY(20.0f);
+ original.setPositionURX(200.0f);
+ original.setPositionURY(300.0f);
+ original.setBgImgScale(1.5f);
+ original.setRenderMode(RenderMode.GRAPHIC_AND_DESCRIPTION);
+ original.setL2Text("Layer 2 text");
+ original.setL4Text("Layer 4 text");
+ original.setL2TextFontSize(14.0f);
+ original.setImgPath("/img.png");
+ original.setBgImgPath("/bg.png");
+ original.setAcro6Layers(true);
+
+ // TSA
+ original.setTimestamp(true);
+ original.setTsaUrl("http://tsa.example.com");
+ original.setTsaServerAuthn(ServerAuthentication.CERTIFICATE);
+ original.setTsaUser("tsaUser");
+ original.setTsaPasswd("tsaPass");
+ original.setTsaCertFileType("PKCS12");
+ original.setTsaCertFile("/tsa-cert.p12");
+ original.setTsaCertFilePwd("tsaCertPwd");
+ original.setTsaPolicy("1.2.3.4");
+ original.setTsaHashAlg("SHA-256");
+
+ // OCSP / CRL
+ original.setOcspEnabled(true);
+ original.setOcspServerUrl("http://ocsp.example.com");
+ original.setCrlEnabled(true);
+
+ // Proxy
+ original.setProxyType(Proxy.Type.HTTP);
+ original.setProxyHost("proxy.example.com");
+ original.setProxyPort(8080);
+
+ // --- Create copy ---
+ BasicSignerOptions copy = original.createCopy();
+
+ // Must be a different object
+ assertNotSame(original, copy);
+
+ // String fields
+ assertEquals(original.getKsType(), copy.getKsType());
+ assertEquals(original.getKsFile(), copy.getKsFile());
+ assertArrayEquals(original.getKsPasswd(), copy.getKsPasswd());
+ assertEquals(original.getKeyAlias(), copy.getKeyAlias());
+ assertEquals(original.getKeyIndex(), copy.getKeyIndex());
+ assertArrayEquals(original.getKeyPasswd(), copy.getKeyPasswd());
+ assertEquals(original.getInFile(), copy.getInFile());
+ assertEquals(original.getOutFile(), copy.getOutFile());
+ assertEquals(original.getSignerName(), copy.getSignerName());
+ assertEquals(original.getReason(), copy.getReason());
+ assertEquals(original.getLocation(), copy.getLocation());
+ assertEquals(original.getContact(), copy.getContact());
+ assertEquals(original.isAppend(), copy.isAppend());
+ assertEquals(original.isAdvanced(), copy.isAdvanced());
+
+ // Encryption
+ assertEquals(original.getPdfEncryption(), copy.getPdfEncryption());
+ assertArrayEquals(original.getPdfOwnerPwd(), copy.getPdfOwnerPwd());
+ assertArrayEquals(original.getPdfUserPwd(), copy.getPdfUserPwd());
+ assertEquals(original.getPdfEncryptionCertFile(), copy.getPdfEncryptionCertFile());
+ assertEquals(original.getCertLevel(), copy.getCertLevel());
+ assertEquals(original.getHashAlgorithm(), copy.getHashAlgorithm());
+ assertEquals(original.isStorePasswords(), copy.isStorePasswords());
+
+ // Rights
+ assertEquals(original.getRightPrinting(), copy.getRightPrinting());
+ assertEquals(original.isRightCopy(), copy.isRightCopy());
+ assertEquals(original.isRightAssembly(), copy.isRightAssembly());
+ assertEquals(original.isRightFillIn(), copy.isRightFillIn());
+ assertEquals(original.isRightScreanReaders(), copy.isRightScreanReaders());
+ assertEquals(original.isRightModifyAnnotations(), copy.isRightModifyAnnotations());
+ assertEquals(original.isRightModifyContents(), copy.isRightModifyContents());
+
+ // Visible signature
+ assertEquals(original.isVisible(), copy.isVisible());
+ assertEquals(original.getPage(), copy.getPage());
+ assertEquals(original.getPositionLLX(), copy.getPositionLLX(), 0.0f);
+ assertEquals(original.getPositionLLY(), copy.getPositionLLY(), 0.0f);
+ assertEquals(original.getPositionURX(), copy.getPositionURX(), 0.0f);
+ assertEquals(original.getPositionURY(), copy.getPositionURY(), 0.0f);
+ assertEquals(original.getBgImgScale(), copy.getBgImgScale(), 0.0f);
+ assertEquals(original.getRenderMode(), copy.getRenderMode());
+ assertEquals(original.getL2Text(), copy.getL2Text());
+ assertEquals(original.getL4Text(), copy.getL4Text());
+ assertEquals(original.getL2TextFontSize(), copy.getL2TextFontSize(), 0.0f);
+ assertEquals(original.getImgPath(), copy.getImgPath());
+ assertEquals(original.getBgImgPath(), copy.getBgImgPath());
+ assertEquals(original.isAcro6Layers(), copy.isAcro6Layers());
+
+ // TSA
+ assertEquals(original.isTimestamp(), copy.isTimestamp());
+ assertEquals(original.getTsaUrl(), copy.getTsaUrl());
+ assertEquals(original.getTsaServerAuthn(), copy.getTsaServerAuthn());
+ assertEquals(original.getTsaUser(), copy.getTsaUser());
+ assertEquals(original.getTsaPasswd(), copy.getTsaPasswd());
+ assertEquals(original.getTsaCertFileType(), copy.getTsaCertFileType());
+ assertEquals(original.getTsaCertFile(), copy.getTsaCertFile());
+ assertEquals(original.getTsaCertFilePwd(), copy.getTsaCertFilePwd());
+ assertEquals(original.getTsaPolicy(), copy.getTsaPolicy());
+ assertEquals(original.getTsaHashAlg(), copy.getTsaHashAlg());
+
+ // OCSP / CRL
+ assertEquals(original.isOcspEnabled(), copy.isOcspEnabled());
+ assertEquals(original.getOcspServerUrl(), copy.getOcspServerUrl());
+ assertEquals(original.isCrlEnabled(), copy.isCrlEnabled());
+
+ // Proxy
+ assertEquals(original.getProxyType(), copy.getProxyType());
+ assertEquals(original.getProxyHost(), copy.getProxyHost());
+ assertEquals(original.getProxyPort(), copy.getProxyPort());
+ }
+
+ @Test
+ public void createCopyShouldDefensivelyCopyCharArrays() {
+ BasicSignerOptions original = new BasicSignerOptions();
+ original.setKsPasswd("secret".toCharArray());
+ original.setKeyPasswd("key".toCharArray());
+ original.setPdfOwnerPwd("owner".toCharArray());
+ original.setPdfUserPwd("user".toCharArray());
+
+ BasicSignerOptions copy = original.createCopy();
+
+ // Arrays should have equal content but be different instances
+ assertArrayEquals(original.getKsPasswd(), copy.getKsPasswd());
+ assertNotSame(original.getKsPasswd(), copy.getKsPasswd());
+
+ assertArrayEquals(original.getKeyPasswd(), copy.getKeyPasswd());
+ assertNotSame(original.getKeyPasswd(), copy.getKeyPasswd());
+
+ assertArrayEquals(original.getPdfOwnerPwd(), copy.getPdfOwnerPwd());
+ assertNotSame(original.getPdfOwnerPwd(), copy.getPdfOwnerPwd());
+
+ assertArrayEquals(original.getPdfUserPwd(), copy.getPdfUserPwd());
+ assertNotSame(original.getPdfUserPwd(), copy.getPdfUserPwd());
+ }
+}
diff --git a/jsignpdf/src/test/java/net/sf/jsignpdf/fx/FxTranslationsTest.java b/jsignpdf/src/test/java/net/sf/jsignpdf/fx/FxTranslationsTest.java
new file mode 100644
index 00000000..daaf6ee6
--- /dev/null
+++ b/jsignpdf/src/test/java/net/sf/jsignpdf/fx/FxTranslationsTest.java
@@ -0,0 +1,321 @@
+package net.sf.jsignpdf.fx;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javafx.application.Platform;
+import javafx.fxml.FXMLLoader;
+import javafx.scene.Node;
+import javafx.scene.Parent;
+import javafx.scene.control.Accordion;
+import javafx.scene.control.Button;
+import javafx.scene.control.CheckBox;
+import javafx.scene.control.Label;
+import javafx.scene.control.Menu;
+import javafx.scene.control.MenuBar;
+import javafx.scene.control.SplitPane;
+import javafx.scene.control.ToolBar;
+import javafx.scene.layout.AnchorPane;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.StackPane;
+import javafx.scene.layout.VBox;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import net.sf.jsignpdf.Constants;
+
+/**
+ * Tests that the JavaFX UI loads correctly with different locales and that
+ * translated text appears in the actual UI nodes.
+ */
+public class FxTranslationsTest {
+
+ private static final String BUNDLE_BASE = Constants.RESOURCE_BUNDLE_BASE;
+
+ private static final Locale[] TEST_LOCALES = {
+ Locale.ENGLISH,
+ new Locale("cs"),
+ new Locale("de"),
+ new Locale("fr"),
+ new Locale("es"),
+ new Locale("ja"),
+ new Locale("zh", "CN"),
+ };
+
+ @BeforeClass
+ public static void initFx() throws Exception {
+ CountDownLatch latch = new CountDownLatch(1);
+ try {
+ Platform.startup(latch::countDown);
+ } catch (IllegalStateException e) {
+ latch.countDown();
+ }
+ latch.await(5, TimeUnit.SECONDS);
+ }
+
+ @Test
+ public void testMainWindowLoadsWithAllLocales() throws Exception {
+ for (Locale locale : TEST_LOCALES) {
+ ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_BASE, locale);
+ Parent root = loadFxml("/net/sf/jsignpdf/fx/view/MainWindow.fxml", bundle);
+ assertNotNull("MainWindow failed to load for locale " + locale, root);
+ }
+ }
+
+ @Test
+ public void testMenuTextsMatchTranslations() throws Exception {
+ for (Locale locale : TEST_LOCALES) {
+ ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_BASE, locale);
+ BorderPane root = (BorderPane) loadFxml("/net/sf/jsignpdf/fx/view/MainWindow.fxml", bundle);
+ MenuBar menuBar = getMenuBar(root);
+
+ assertEquals("File menu for " + locale,
+ bundle.getString("jfx.gui.menu.file"), menuBar.getMenus().get(0).getText());
+ assertEquals("View menu for " + locale,
+ bundle.getString("jfx.gui.menu.view"), menuBar.getMenus().get(1).getText());
+ assertEquals("Signing menu for " + locale,
+ bundle.getString("jfx.gui.menu.signing"), menuBar.getMenus().get(2).getText());
+ assertEquals("Help menu for " + locale,
+ bundle.getString("jfx.gui.menu.help"), menuBar.getMenus().get(3).getText());
+ }
+ }
+
+ @Test
+ public void testMenuItemTextsMatchTranslations() throws Exception {
+ for (Locale locale : TEST_LOCALES) {
+ ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_BASE, locale);
+ BorderPane root = (BorderPane) loadFxml("/net/sf/jsignpdf/fx/view/MainWindow.fxml", bundle);
+ Menu fileMenu = getMenuBar(root).getMenus().get(0);
+
+ assertEquals("Open for " + locale,
+ bundle.getString("jfx.gui.menu.file.open"), fileMenu.getItems().get(0).getText());
+ assertEquals("Close for " + locale,
+ bundle.getString("jfx.gui.menu.file.close"), fileMenu.getItems().get(1).getText());
+ // index 2 = separator, index 3 = Recent Files submenu, index 4 = separator
+ assertEquals("Exit for " + locale,
+ bundle.getString("jfx.gui.menu.file.exit"), fileMenu.getItems().get(5).getText());
+ }
+ }
+
+ @Test
+ public void testToolbarTextsMatchTranslations() throws Exception {
+ for (Locale locale : TEST_LOCALES) {
+ ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_BASE, locale);
+ BorderPane root = (BorderPane) loadFxml("/net/sf/jsignpdf/fx/view/MainWindow.fxml", bundle);
+ ToolBar toolBar = getToolBar(root);
+
+ // First item is the Open button
+ Button openBtn = (Button) toolBar.getItems().get(0);
+ assertEquals("Open button for " + locale,
+ bundle.getString("jfx.gui.toolbar.open"), openBtn.getText());
+
+ // Last item is the Sign button
+ Button signBtn = (Button) toolBar.getItems().get(toolBar.getItems().size() - 1);
+ assertEquals("Sign button for " + locale,
+ bundle.getString("jfx.gui.toolbar.sign"), signBtn.getText());
+ }
+ }
+
+ @Test
+ public void testAccordionPanelTitlesMatchTranslations() throws Exception {
+ for (Locale locale : TEST_LOCALES) {
+ ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_BASE, locale);
+ BorderPane root = (BorderPane) loadFxml("/net/sf/jsignpdf/fx/view/MainWindow.fxml", bundle);
+ Accordion accordion = getAccordion(root);
+ assertNotNull("Accordion not found for " + locale, accordion);
+
+ assertEquals("Certificate panel for " + locale,
+ bundle.getString("jfx.gui.panel.certificate"),
+ accordion.getPanes().get(0).getText());
+ assertEquals("Signature panel for " + locale,
+ bundle.getString("jfx.gui.panel.signatureAppearance"),
+ accordion.getPanes().get(1).getText());
+ assertEquals("TSA panel for " + locale,
+ bundle.getString("jfx.gui.panel.timestampValidation"),
+ accordion.getPanes().get(2).getText());
+ assertEquals("Encryption panel for " + locale,
+ bundle.getString("jfx.gui.panel.encryptionRights"),
+ accordion.getPanes().get(3).getText());
+ }
+ }
+
+ @Test
+ public void testDropHintMatchesTranslation() throws Exception {
+ for (Locale locale : TEST_LOCALES) {
+ ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_BASE, locale);
+ BorderPane root = (BorderPane) loadFxml("/net/sf/jsignpdf/fx/view/MainWindow.fxml", bundle);
+ Label dropHint = getDropHintLabel(root);
+ assertNotNull("Drop hint not found for " + locale, dropHint);
+ assertEquals("Drop hint for " + locale,
+ bundle.getString("jfx.gui.dropHint"), dropHint.getText());
+ }
+ }
+
+ @Test
+ public void testCertificateSettingsLabels() throws Exception {
+ for (Locale locale : TEST_LOCALES) {
+ ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_BASE, locale);
+ VBox root = (VBox) loadFxml("/net/sf/jsignpdf/fx/view/CertificateSettings.fxml", bundle);
+ assertNotNull("CertificateSettings load failed for " + locale, root);
+
+ // First child is the "Keystore type:" label
+ Label ksTypeLabel = (Label) root.getChildren().get(0);
+ assertEquals("Keystore type label for " + locale,
+ bundle.getString("jfx.gui.cert.keystoreType"), ksTypeLabel.getText());
+
+ // Find "Store passwords" checkbox (last child)
+ CheckBox storePasswords = (CheckBox) root.getChildren().get(root.getChildren().size() - 1);
+ assertEquals("Store passwords checkbox for " + locale,
+ bundle.getString("jfx.gui.cert.storePasswords"), storePasswords.getText());
+ }
+ }
+
+ @Test
+ public void testSignatureSettingsLabels() throws Exception {
+ for (Locale locale : TEST_LOCALES) {
+ ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_BASE, locale);
+ VBox root = (VBox) loadFxml("/net/sf/jsignpdf/fx/view/SignatureSettings.fxml", bundle);
+ assertNotNull("SignatureSettings load failed for " + locale, root);
+
+ // First child is the "Enable visible signature" checkbox
+ CheckBox visibleSig = (CheckBox) root.getChildren().get(0);
+ assertEquals("Enable visible sig for " + locale,
+ bundle.getString("jfx.gui.sig.enableVisible"), visibleSig.getText());
+ }
+ }
+
+ @Test
+ public void testTsaSettingsLabels() throws Exception {
+ for (Locale locale : TEST_LOCALES) {
+ ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_BASE, locale);
+ VBox root = (VBox) loadFxml("/net/sf/jsignpdf/fx/view/TsaSettings.fxml", bundle);
+ assertNotNull("TsaSettings load failed for " + locale, root);
+
+ // First child is the "Enable Timestamp (TSA)" checkbox
+ CheckBox tsaEnabled = (CheckBox) root.getChildren().get(0);
+ assertEquals("TSA checkbox for " + locale,
+ bundle.getString("jfx.gui.tsa.enableTimestamp"), tsaEnabled.getText());
+ }
+ }
+
+ @Test
+ public void testEncryptionSettingsLabels() throws Exception {
+ for (Locale locale : TEST_LOCALES) {
+ ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_BASE, locale);
+ VBox root = (VBox) loadFxml("/net/sf/jsignpdf/fx/view/EncryptionSettings.fxml", bundle);
+ assertNotNull("EncryptionSettings load failed for " + locale, root);
+
+ // First child is the "PDF Encryption:" label
+ Label encLabel = (Label) root.getChildren().get(0);
+ assertEquals("PDF Encryption label for " + locale,
+ bundle.getString("jfx.gui.enc.pdfEncryption"), encLabel.getText());
+ }
+ }
+
+ @Test
+ public void testEnglishSpecificTexts() throws Exception {
+ ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_BASE, Locale.ENGLISH);
+ BorderPane root = (BorderPane) loadFxml("/net/sf/jsignpdf/fx/view/MainWindow.fxml", bundle);
+ MenuBar menuBar = getMenuBar(root);
+
+ assertEquals("File", menuBar.getMenus().get(0).getText());
+ assertEquals("View", menuBar.getMenus().get(1).getText());
+ assertEquals("Signing", menuBar.getMenus().get(2).getText());
+ assertEquals("Help", menuBar.getMenus().get(3).getText());
+ assertEquals("Drop a PDF file here or use File > Open", getDropHintLabel(root).getText());
+ }
+
+ @Test
+ public void testGermanSpecificTexts() throws Exception {
+ ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_BASE, new Locale("de"));
+ BorderPane root = (BorderPane) loadFxml("/net/sf/jsignpdf/fx/view/MainWindow.fxml", bundle);
+ MenuBar menuBar = getMenuBar(root);
+
+ assertEquals("Datei", menuBar.getMenus().get(0).getText());
+ assertEquals("Ansicht", menuBar.getMenus().get(1).getText());
+ assertEquals("Signierung", menuBar.getMenus().get(2).getText());
+ assertEquals("Hilfe", menuBar.getMenus().get(3).getText());
+ }
+
+ @Test
+ public void testCzechSpecificTexts() throws Exception {
+ ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_BASE, new Locale("cs"));
+ BorderPane root = (BorderPane) loadFxml("/net/sf/jsignpdf/fx/view/MainWindow.fxml", bundle);
+ MenuBar menuBar = getMenuBar(root);
+ Accordion accordion = getAccordion(root);
+
+ assertEquals("Soubor", menuBar.getMenus().get(0).getText());
+ assertEquals("Certifik\u00e1t", accordion.getPanes().get(0).getText());
+ }
+
+ // --- Helper methods for navigating the node tree ---
+
+ private MenuBar getMenuBar(BorderPane root) {
+ VBox topBox = (VBox) root.getTop();
+ return (MenuBar) topBox.getChildren().get(0);
+ }
+
+ private ToolBar getToolBar(BorderPane root) {
+ VBox topBox = (VBox) root.getTop();
+ return (ToolBar) topBox.getChildren().get(1);
+ }
+
+ private Accordion getAccordion(BorderPane root) {
+ // center -> verticalSplit -> splitPane -> AnchorPane -> Accordion
+ SplitPane verticalSplit = (SplitPane) root.getCenter();
+ SplitPane splitPane = (SplitPane) verticalSplit.getItems().get(0);
+ AnchorPane sidePanel = (AnchorPane) splitPane.getItems().get(0);
+ return (Accordion) sidePanel.getChildren().get(0);
+ }
+
+ private Label getDropHintLabel(BorderPane root) {
+ // center -> verticalSplit -> splitPane -> ScrollPane -> StackPane -> Label
+ SplitPane verticalSplit = (SplitPane) root.getCenter();
+ SplitPane splitPane = (SplitPane) verticalSplit.getItems().get(0);
+ javafx.scene.control.ScrollPane scrollPane =
+ (javafx.scene.control.ScrollPane) splitPane.getItems().get(1);
+ StackPane pdfArea = (StackPane) scrollPane.getContent();
+ for (Node child : pdfArea.getChildren()) {
+ if (child instanceof Label) {
+ return (Label) child;
+ }
+ }
+ return null;
+ }
+
+ private Parent loadFxml(String fxmlPath, ResourceBundle bundle) throws Exception {
+ CountDownLatch latch = new CountDownLatch(1);
+ AtomicReference result = new AtomicReference<>();
+ AtomicReference error = new AtomicReference<>();
+
+ Platform.runLater(() -> {
+ try {
+ FXMLLoader loader = new FXMLLoader(
+ getClass().getResource(fxmlPath), bundle);
+ result.set(loader.load());
+ } catch (Throwable t) {
+ error.set(t);
+ } finally {
+ latch.countDown();
+ }
+ });
+
+ if (!latch.await(10, TimeUnit.SECONDS)) {
+ fail("FXML loading timed out for " + fxmlPath);
+ }
+ if (error.get() != null) {
+ fail("FXML loading failed for " + fxmlPath + " with " + bundle.getLocale()
+ + ": " + error.get().getMessage());
+ }
+ return result.get();
+ }
+}
diff --git a/jsignpdf/src/test/java/net/sf/jsignpdf/utils/KeyStoreUtilsTest.java b/jsignpdf/src/test/java/net/sf/jsignpdf/utils/KeyStoreUtilsTest.java
index 9540a661..bd3ab29f 100644
--- a/jsignpdf/src/test/java/net/sf/jsignpdf/utils/KeyStoreUtilsTest.java
+++ b/jsignpdf/src/test/java/net/sf/jsignpdf/utils/KeyStoreUtilsTest.java
@@ -4,14 +4,21 @@
import static net.sf.jsignpdf.TestConstants.KEYSTORE_JKS;
import static net.sf.jsignpdf.TestConstants.KEYSTORE_PKCS12;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.security.KeyStore;
import java.util.Arrays;
import java.util.List;
import java.util.SortedSet;
import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.Rule;
+import net.sf.jsignpdf.BasicSignerOptions;
import net.sf.jsignpdf.TestConstants;
/**
@@ -21,6 +28,9 @@
*/
public class KeyStoreUtilsTest {
+ @Rule
+ public TemporaryFolder tempFolder = new TemporaryFolder();
+
/**
* Tests {@link KeyStoreUtils#getKeyStores()}.
*/
@@ -51,4 +61,27 @@ public void testGetKeyAliases() {
}
}
}
+
+ /**
+ * Tests that {@link KeyStoreUtils#getPkInfo} returns null (instead of throwing NPE)
+ * when the keystore is empty and no alias can be resolved.
+ */
+ @Test
+ public void testGetPkInfoReturnsNullForEmptyKeystore() throws Exception {
+ // Create an empty PKCS12 keystore
+ File emptyKs = tempFolder.newFile("empty.p12");
+ char[] password = "testpass".toCharArray();
+ KeyStore ks = KeyStore.getInstance("PKCS12");
+ ks.load(null, password);
+ try (FileOutputStream fos = new FileOutputStream(emptyKs)) {
+ ks.store(fos, password);
+ }
+
+ BasicSignerOptions opts = new BasicSignerOptions();
+ opts.setKsType(KEYSTORE_PKCS12);
+ opts.setKsFile(emptyKs.getAbsolutePath());
+ opts.setKsPasswd(password);
+ // No alias set, empty keystore -> getKeyAliasInternal returns null
+ assertNull(KeyStoreUtils.getPkInfo(opts));
+ }
}
diff --git a/pom.xml b/pom.xml
index d18a8ce1..52464f41 100644
--- a/pom.xml
+++ b/pom.xml
@@ -31,6 +31,7 @@
3.20.0
1.3.30
4.13.2
+ 17.0.15