51 changed files with 703 additions and 95 deletions
+5 -5
View File
@@ -1,7 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<rect x="3" y="4" width="18" height="16" rx="2.5" fill="none" stroke="currentColor" stroke-width="2"/>
<circle cx="12" cy="10" r="2.5" fill="none" stroke="#0288d1" stroke-width="1.8"/>
<path d="M 10.5 12.2 L 9.5 17 L 12 15.5 L 14.5 17 L 13.5 12.2" fill="none" stroke="#0288d1" stroke-width="1.8" stroke-linejoin="round"/>
<line x1="6" y1="7" x2="8" y2="7" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
<line x1="16" y1="7" x2="18" y2="7" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
<rect x="3.5" y="2.5" width="17" height="19" rx="2.5" fill="none" stroke="currentColor" stroke-width="2"/>
<line x1="7" y1="6.5" x2="13" y2="6.5" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
<line x1="7" y1="9.5" x2="11" y2="9.5" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" opacity="0.6"/>
<circle cx="14.5" cy="14.5" r="3.5" fill="none" stroke="#0288d1" stroke-width="1.8"/>
<path d="M 13 14.5 L 14.2 15.7 L 16.5 13.2" fill="none" stroke="#0288d1" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 625 B

After

Width:  |  Height:  |  Size: 659 B

+5 -3
View File
@@ -1,5 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<circle cx="12" cy="10" r="7.5" fill="none" stroke="#f59e0b" stroke-width="2"/>
<circle cx="12" cy="10" r="4.5" fill="none" stroke="#f59e0b" stroke-width="1.2" stroke-dasharray="2 1.5"/>
<path d="M 9.5 15.5 L 7 21.5 L 12 19 L 17 21.5 L 14.5 15.5" fill="none" stroke="#d97706" stroke-width="1.8" stroke-linejoin="round"/>
<rect x="2.5" y="4.5" width="19" height="15" rx="3" fill="none" stroke="currentColor" stroke-width="2"/>
<path d="M 6 13.5 C 7.5 10 9 10 10.5 13 C 11.5 15 13 11 15 12" fill="none" stroke="#0288d1" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="17.5" cy="8.5" r="1.5" fill="#f59e0b"/>
<line x1="6" y1="8.5" x2="13" y2="8.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" opacity="0.5"/>
<line x1="6" y1="16" x2="18" y2="16" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" opacity="0.4"/>
</svg>

Before

Width:  |  Height:  |  Size: 418 B

After

Width:  |  Height:  |  Size: 654 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 45 KiB

@@ -14,6 +14,8 @@ import javafx.scene.shape.Circle;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.SVGPath;
import javafx.scene.shape.StrokeLineCap;
import javafx.scene.shape.StrokeLineJoin;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
@@ -477,11 +479,21 @@ public final class SvgIcons {
StackPane box = new StackPane();
box.setPrefSize(24, 24);
Text code = new Text("</>");
code.setFont(Font.font("Segoe UI", FontWeight.BOLD, 12));
code.setFill(Color.web("#0288d1"));
SVGPath frame = new SVGPath();
frame.setContent("M 3 5 C 3 3.9 3.9 3 5 3 L 19 3 C 20.1 3 21 3.9 21 5 L 21 19 C 21 20.1 20.1 21 19 21 L 5 21 C 3.9 21 3 20.1 3 19 Z");
frame.setFill(Color.TRANSPARENT);
frame.setStroke(Color.web("#1e293b"));
frame.setStrokeWidth(1.8);
box.getChildren().add(code);
SVGPath prompt = new SVGPath();
prompt.setContent("M 7 9 L 10 12 L 7 15 M 12 15 L 16 15");
prompt.setFill(Color.TRANSPARENT);
prompt.setStroke(Color.web("#0288d1"));
prompt.setStrokeWidth(1.8);
prompt.setStrokeLineCap(StrokeLineCap.ROUND);
prompt.setStrokeLineJoin(StrokeLineJoin.ROUND);
box.getChildren().addAll(frame, prompt);
return box;
}
@@ -538,20 +550,21 @@ public final class SvgIcons {
StackPane box = new StackPane();
box.setPrefSize(24, 24);
SVGPath folder = new SVGPath();
folder.setContent("M 2 5 L 8 5 L 10 7 L 22 7 L 22 20 L 2 20 Z");
folder.setFill(Color.web("#e1f5fe"));
folder.setStroke(Color.web("#0288d1"));
folder.setStrokeWidth(1.5);
SVGPath certFrame = new SVGPath();
certFrame.setContent("M 4 4 C 4 3 5 2 6 2 L 18 2 C 19 2 20 3 20 4 L 20 20 C 20 21 19 22 18 22 L 6 22 C 5 22 4 21 4 20 Z M 7 6 L 14 6 M 7 9 L 12 9");
certFrame.setFill(Color.TRANSPARENT);
certFrame.setStroke(Color.web("#1e293b"));
certFrame.setStrokeWidth(1.8);
Rectangle lock = new Rectangle(7, 6);
lock.setArcWidth(2);
lock.setArcHeight(2);
lock.setFill(Color.web("#0288d1"));
lock.setTranslateX(3);
lock.setTranslateY(2);
SVGPath badge = new SVGPath();
badge.setContent("M 15 13 A 3.2 3.2 0 1 1 15 13.01 M 13.5 15 L 14.8 16.2 L 17 14");
badge.setFill(Color.TRANSPARENT);
badge.setStroke(Color.web("#0288d1"));
badge.setStrokeWidth(1.6);
badge.setStrokeLineCap(StrokeLineCap.ROUND);
badge.setStrokeLineJoin(StrokeLineJoin.ROUND);
box.getChildren().addAll(folder, lock);
box.getChildren().addAll(certFrame, badge);
return box;
}
@@ -624,23 +637,31 @@ public final class SvgIcons {
StackPane box = new StackPane();
box.setPrefSize(38, 38);
SVGPath ribbon = new SVGPath();
ribbon.setContent("M 14 26 L 19 36 L 24 26 Z M 9 26 L 12 34 L 15 26 Z");
ribbon.setFill(Color.web("#f59e0b"));
SVGPath frame = new SVGPath();
frame.setContent("M 6 8 C 4.9 8 4 8.9 4 10 L 4 28 C 4 29.1 4.9 30 6 30 L 32 30 C 33.1 30 34 29.1 34 28 L 34 10 C 34 8.9 33.1 8 32 8 Z");
frame.setFill(Color.TRANSPARENT);
frame.setStroke(Color.web("#1e293b"));
frame.setStrokeWidth(1.8);
Circle sealCircle = new Circle(13);
sealCircle.setFill(Color.web("#d97706"));
sealCircle.setStroke(Color.web("#fbbf24"));
sealCircle.setStrokeWidth(1.6);
sealCircle.setTranslateY(-4);
SVGPath lines = new SVGPath();
lines.setContent("M 8 13 L 20 13 M 8 25 L 30 25");
lines.setFill(Color.TRANSPARENT);
lines.setStroke(Color.web("#64748b"));
lines.setStrokeWidth(1.4);
lines.setStrokeLineCap(StrokeLineCap.ROUND);
SVGPath star = new SVGPath();
star.setContent("M 19 8 L 21 13 L 26 13 L 22 16 L 24 21 L 19 18 L 14 21 L 16 16 L 12 13 L 17 13 Z");
star.setFill(Color.web("#ffffff"));
star.setTranslateX(-9);
star.setTranslateY(-14);
Circle dot = new Circle(28, 13, 2);
dot.setFill(Color.web("#f59e0b"));
box.getChildren().addAll(ribbon, sealCircle, star);
SVGPath signature = new SVGPath();
signature.setContent("M 8 20 C 11 16 13 16 15 20 C 17 23 20 17 23 18");
signature.setFill(Color.TRANSPARENT);
signature.setStroke(Color.web("#0288d1"));
signature.setStrokeWidth(2.0);
signature.setStrokeLineCap(StrokeLineCap.ROUND);
signature.setStrokeLineJoin(StrokeLineJoin.ROUND);
box.getChildren().addAll(frame, lines, dot, signature);
return box;
}
@@ -41,7 +41,6 @@ public class A1PasswordDialog {
VBox root = new VBox(16);
root.getStyleClass().add("dialog-container");
root.setPadding(new Insets(24));
root.setPrefWidth(440);
Label header = new Label("IMPORTAR CERTIFICADO A1");
header.getStyleClass().add("dialog-header");
@@ -70,14 +69,19 @@ public class A1PasswordDialog {
actionsRow.setAlignment(Pos.CENTER_RIGHT);
Button btnCancel = new Button("Cancelar");
btnCancel.getStyleClass().add("btn-secondary");
btnCancel.getStyleClass().addAll("btn-ghost", "btn-dialog");
btnCancel.setMinWidth(javafx.scene.layout.Region.USE_PREF_SIZE);
btnCancel.setOnAction(e -> {
passwordFuture.complete(null);
stage.close();
});
HBox spacer = new HBox();
HBox.setHgrow(spacer, Priority.ALWAYS);
Button btnConfirm = new Button("Importar");
btnConfirm.getStyleClass().add("btn-primary");
btnConfirm.getStyleClass().addAll("btn-primary", "btn-dialog");
btnConfirm.setMinWidth(javafx.scene.layout.Region.USE_PREF_SIZE);
btnConfirm.setDefaultButton(true);
btnConfirm.setOnAction(e -> {
String text = passwordField.getText();
@@ -85,7 +89,7 @@ public class A1PasswordDialog {
stage.close();
});
actionsRow.getChildren().addAll(btnCancel, btnConfirm);
actionsRow.getChildren().addAll(btnCancel, spacer, btnConfirm);
root.getChildren().addAll(header, desc, fileBox, inputGroup, actionsRow);
@@ -93,6 +97,7 @@ public class A1PasswordDialog {
ThemeManager.applyTheme(scene);
stage.setScene(scene);
stage.sizeToScene();
stage.setOnCloseRequest(e -> passwordFuture.complete(null));
}
@@ -100,4 +105,8 @@ public class A1PasswordDialog {
stage.show();
return passwordFuture;
}
public Stage getStage() {
return this.stage;
}
}
@@ -95,20 +95,25 @@ public class ApplicationApprovalDialog {
Button btnReject = new Button("Recusar Acesso");
btnReject.getStyleClass().addAll("btn-danger-outline", "btn-dialog");
btnReject.setMinWidth(javafx.scene.layout.Region.USE_PREF_SIZE);
btnReject.setOnAction(e -> {
approvalFuture.complete(false);
stage.close();
});
HBox spacer = new HBox();
HBox.setHgrow(spacer, Priority.ALWAYS);
Button btnAuthorize = new Button("Autorizar Conexão");
btnAuthorize.getStyleClass().addAll("btn-primary", "btn-dialog");
btnAuthorize.setMinWidth(javafx.scene.layout.Region.USE_PREF_SIZE);
btnAuthorize.setDefaultButton(true);
btnAuthorize.setOnAction(e -> {
approvalFuture.complete(true);
stage.close();
});
actionsRow.getChildren().addAll(btnReject, btnAuthorize);
actionsRow.getChildren().addAll(btnReject, spacer, btnAuthorize);
root.getChildren().addAll(header, detailsBox, secWarning, actionsRow);
@@ -116,6 +121,7 @@ public class ApplicationApprovalDialog {
ThemeManager.applyTheme(scene);
stage.setScene(scene);
stage.sizeToScene();
stage.setOnCloseRequest(e -> approvalFuture.complete(false));
}
@@ -124,4 +130,8 @@ public class ApplicationApprovalDialog {
stage.toFront();
return approvalFuture;
}
public Stage getStage() {
return this.stage;
}
}
@@ -245,6 +245,7 @@ public final class BatchSigningDialog {
btnChooseOutputDir = new Button("Selecionar...");
btnChooseOutputDir.getStyleClass().add("btn-secondary");
btnChooseOutputDir.setMinWidth(javafx.scene.layout.Region.USE_PREF_SIZE);
btnChooseOutputDir.setOnAction(e -> handleChooseOutputDir());
outputRow.getChildren().addAll(lblOutput, txtOutputDir, btnChooseOutputDir);
@@ -266,16 +267,21 @@ public final class BatchSigningDialog {
footer.setAlignment(Pos.CENTER_RIGHT);
Button btnClose = new Button("Fechar");
btnClose.getStyleClass().add("btn-secondary");
btnClose.getStyleClass().addAll("btn-ghost", "btn-dialog");
btnClose.setMinWidth(javafx.scene.layout.Region.USE_PREF_SIZE);
btnClose.setOnAction(e -> {
if (!isRunning) stage.close();
});
HBox spacer = new HBox();
HBox.setHgrow(spacer, Priority.ALWAYS);
btnStart = new Button("Iniciar Assinatura em Lote");
btnStart.getStyleClass().add("btn-primary");
btnStart.getStyleClass().addAll("btn-primary", "btn-dialog");
btnStart.setMinWidth(javafx.scene.layout.Region.USE_PREF_SIZE);
btnStart.setOnAction(e -> startBatchSigning());
footer.getChildren().addAll(btnClose, btnStart);
footer.getChildren().addAll(btnClose, spacer, btnStart);
root.getChildren().addAll(header, fileActions, tableView, configBox, progressBox, footer);
@@ -283,6 +289,7 @@ public final class BatchSigningDialog {
ThemeManager.applyTheme(scene);
stage.setScene(scene);
stage.sizeToScene();
}
private void handleAddFiles() {
@@ -129,8 +129,7 @@ public class CertificateDetailsDialog {
Button btnClose = new Button(" Fechar", SvgIcons.closeIcon(13));
btnClose.getStyleClass().addAll("btn-ghost", "btn-dialog");
btnClose.setPrefWidth(110);
btnClose.setMinWidth(110);
btnClose.setMinWidth(javafx.scene.layout.Region.USE_PREF_SIZE);
btnClose.setOnAction(e -> stage.close());
actionsRow.getChildren().add(btnClose);
@@ -141,12 +140,17 @@ public class CertificateDetailsDialog {
ThemeManager.applyTheme(scene);
stage.setScene(scene);
stage.sizeToScene();
}
public void show() {
stage.show();
}
public Stage getStage() {
return this.stage;
}
private void addField(GridPane grid, int row, String label, String value) {
Label lbl = new Label(label);
lbl.getStyleClass().add("dialog-field-title");
@@ -75,10 +75,12 @@ public final class CertificatesManagerDialog {
Button btnAddA1 = new Button("Importar A1 (.pfx / .p12)...");
btnAddA1.getStyleClass().add("btn-primary");
btnAddA1.setMinWidth(javafx.scene.layout.Region.USE_PREF_SIZE);
btnAddA1.setOnAction(e -> handleImportA1());
Button btnRefresh = new Button(" Atualizar Lista", SvgIcons.refreshIcon(14));
btnRefresh.getStyleClass().add("btn-secondary");
btnRefresh.setMinWidth(javafx.scene.layout.Region.USE_PREF_SIZE);
btnRefresh.setOnAction(e -> refreshList());
actions.getChildren().addAll(btnAddA1, btnRefresh);
@@ -95,6 +97,7 @@ public final class CertificatesManagerDialog {
footer.setAlignment(Pos.CENTER_RIGHT);
Button btnClose = new Button(" Fechar", SvgIcons.closeIcon(13));
btnClose.getStyleClass().add("btn-secondary");
btnClose.setMinWidth(javafx.scene.layout.Region.USE_PREF_SIZE);
btnClose.setOnAction(e -> stage.close());
footer.getChildren().add(btnClose);
@@ -104,6 +107,7 @@ public final class CertificatesManagerDialog {
ThemeManager.applyTheme(scene);
stage.setScene(scene);
stage.sizeToScene();
}
private void refreshList() {
@@ -189,4 +193,8 @@ public final class CertificatesManagerDialog {
public void show() {
stage.show();
}
public Stage getStage() {
return this.stage;
}
}
@@ -37,8 +37,6 @@ public final class ExitConfirmationDialog {
}
this.stage.setTitle("CyberCore Signer — Encerrar ou Manter na Bandeja");
this.stage.setResizable(false);
this.stage.setMinWidth(520);
this.stage.setMinHeight(190);
initLayout();
}
@@ -71,6 +69,7 @@ public final class ExitConfirmationDialog {
Button btnCancel = new Button("Cancelar");
btnCancel.getStyleClass().addAll("btn-ghost", "btn-dialog");
btnCancel.setMinWidth(javafx.scene.layout.Region.USE_PREF_SIZE);
btnCancel.setOnAction(e -> {
chosenAction = ExitChoice.CANCEL;
stage.close();
@@ -81,6 +80,7 @@ public final class ExitConfirmationDialog {
Button btnExit = new Button("Encerrar Definitivamente");
btnExit.getStyleClass().addAll("btn-danger-outline", "btn-dialog");
btnExit.setMinWidth(javafx.scene.layout.Region.USE_PREF_SIZE);
btnExit.setOnAction(e -> {
chosenAction = ExitChoice.EXIT_COMPLETELY;
stage.close();
@@ -88,6 +88,7 @@ public final class ExitConfirmationDialog {
Button btnMinimize = new Button("Minimizar para a Bandeja");
btnMinimize.getStyleClass().addAll("btn-primary", "btn-dialog");
btnMinimize.setMinWidth(javafx.scene.layout.Region.USE_PREF_SIZE);
btnMinimize.setDefaultButton(true);
btnMinimize.setOnAction(e -> {
chosenAction = ExitChoice.MINIMIZE_TO_TRAY;
@@ -101,6 +102,7 @@ public final class ExitConfirmationDialog {
Scene scene = new Scene(root);
ThemeManager.applyTheme(scene);
stage.setScene(scene);
stage.sizeToScene();
stage.setOnCloseRequest(e -> chosenAction = ExitChoice.CANCEL);
}
@@ -112,6 +112,7 @@ public final class FileSignDialog {
Button btnBrowse = new Button("Procurar...");
btnBrowse.getStyleClass().add("btn-secondary");
btnBrowse.setMinWidth(javafx.scene.layout.Region.USE_PREF_SIZE);
btnBrowse.setOnAction(e -> handleBrowseFile());
fileRow.getChildren().addAll(txtFilePath, btnBrowse);
@@ -159,15 +160,20 @@ public final class FileSignDialog {
footer.setAlignment(Pos.CENTER_RIGHT);
Button btnCancel = new Button("Cancelar");
btnCancel.getStyleClass().add("btn-secondary");
btnCancel.getStyleClass().addAll("btn-ghost", "btn-dialog");
btnCancel.setMinWidth(javafx.scene.layout.Region.USE_PREF_SIZE);
btnCancel.setOnAction(e -> stage.close());
HBox spacer = new HBox();
HBox.setHgrow(spacer, Priority.ALWAYS);
Button btnSign = new Button("Assinar Documento");
btnSign.getStyleClass().add("btn-primary");
btnSign.getStyleClass().addAll("btn-primary", "btn-dialog");
btnSign.setMinWidth(javafx.scene.layout.Region.USE_PREF_SIZE);
btnSign.setDefaultButton(true);
btnSign.setOnAction(e -> executeSignature());
footer.getChildren().addAll(btnCancel, btnSign);
footer.getChildren().addAll(btnCancel, spacer, btnSign);
root.getChildren().addAll(header, fileBox, certBox, footer);
@@ -175,6 +181,7 @@ public final class FileSignDialog {
ThemeManager.applyTheme(scene);
stage.setScene(scene);
stage.sizeToScene();
}
private void handleBrowseFile() {
@@ -257,4 +264,8 @@ public final class FileSignDialog {
public void show() {
stage.show();
}
public Stage getStage() {
return this.stage;
}
}
@@ -64,7 +64,7 @@ public final class LogsViewerDialog {
Button btnCopy = new Button("Copiar");
btnCopy.getStyleClass().addAll("btn-secondary", "btn-dialog");
btnCopy.setPrefWidth(90);
btnCopy.setMinWidth(javafx.scene.layout.Region.USE_PREF_SIZE);
btnCopy.setOnAction(e -> {
javafx.scene.input.ClipboardContent content = new javafx.scene.input.ClipboardContent();
content.putString(txtLogs.getText());
@@ -77,7 +77,7 @@ public final class LogsViewerDialog {
Button btnClear = new Button("Limpar");
btnClear.getStyleClass().addAll("btn-secondary", "btn-dialog");
btnClear.setPrefWidth(90);
btnClear.setMinWidth(javafx.scene.layout.Region.USE_PREF_SIZE);
btnClear.setOnAction(e -> {
br.com.cybercore.signer.core.log.AppLogBuffer.clear();
loadLogs();
@@ -85,15 +85,18 @@ public final class LogsViewerDialog {
Button btnRefresh = new Button("Atualizar");
btnRefresh.getStyleClass().addAll("btn-secondary", "btn-dialog");
btnRefresh.setPrefWidth(100);
btnRefresh.setMinWidth(javafx.scene.layout.Region.USE_PREF_SIZE);
btnRefresh.setOnAction(e -> loadLogs());
HBox spacer = new HBox();
HBox.setHgrow(spacer, Priority.ALWAYS);
Button btnClose = new Button(" Fechar", SvgIcons.closeIcon(13));
btnClose.getStyleClass().addAll("btn-secondary", "btn-dialog");
btnClose.setPrefWidth(100);
btnClose.getStyleClass().addAll("btn-ghost", "btn-dialog");
btnClose.setMinWidth(javafx.scene.layout.Region.USE_PREF_SIZE);
btnClose.setOnAction(e -> stage.close());
footer.getChildren().addAll(btnCopy, btnClear, btnRefresh, btnClose);
footer.getChildren().addAll(btnCopy, btnClear, btnRefresh, spacer, btnClose);
root.getChildren().addAll(header, txtLogs, footer);
@@ -101,6 +104,7 @@ public final class LogsViewerDialog {
ThemeManager.applyTheme(scene);
stage.setScene(scene);
stage.sizeToScene();
}
private void loadLogs() {
@@ -127,4 +131,8 @@ public final class LogsViewerDialog {
public void show() {
stage.show();
}
public Stage getStage() {
return this.stage;
}
}
@@ -81,9 +81,19 @@ public final class MainAppView {
ColumnConstraints col = new ColumnConstraints();
col.setHgrow(Priority.ALWAYS);
col.setPercentWidth(33.33);
col.setFillWidth(true);
actionGrid.getColumnConstraints().add(col);
}
for (int i = 0; i < 2; i++) {
javafx.scene.layout.RowConstraints row = new javafx.scene.layout.RowConstraints();
row.setVgrow(Priority.NEVER);
row.setMinHeight(68);
row.setPrefHeight(Region.USE_COMPUTED_SIZE);
row.setFillHeight(true);
actionGrid.getRowConstraints().add(row);
}
// Linha 0: Operações de Assinatura
actionGrid.add(createActionButton(Icons.pdf(Icons.SIZE_40), "Assinar\nPDF", () -> trigger(onSignPdf)), 0, 0);
actionGrid.add(createActionButton(Icons.xml(Icons.SIZE_40), "Assinar\nXML", () -> trigger(onSignXml)), 1, 0);
@@ -211,8 +221,8 @@ public final class MainAppView {
Button btn = new Button();
btn.getStyleClass().add("cyber-action-card");
btn.setMaxWidth(Double.MAX_VALUE);
btn.setPrefHeight(72);
btn.setMinHeight(68);
btn.setPrefHeight(68);
btn.setMinHeight(Region.USE_PREF_SIZE);
HBox content = new HBox(12);
content.setAlignment(Pos.CENTER_LEFT);
@@ -245,7 +255,7 @@ public final class MainAppView {
Button btn = new Button();
btn.getStyleClass().add("cyber-side-card");
btn.setPrefHeight(42);
btn.setMinHeight(42);
btn.setMinHeight(40);
btn.setMaxWidth(Double.MAX_VALUE);
HBox content = new HBox(12);
@@ -304,13 +304,12 @@ public final class PdfCertificateSignDialog {
btnCancel = new Button("Cancelar");
btnCancel.getStyleClass().addAll("btn-ghost", "btn-dialog");
btnCancel.setMinWidth(110);
btnCancel.setMinWidth(javafx.scene.layout.Region.USE_PREF_SIZE);
btnCancel.setOnAction(e -> stage.close());
btnSign = new Button("Assinar Documento PDF");
btnSign.getStyleClass().addAll("btn-primary", "btn-dialog-wide");
btnSign.setMinWidth(220);
btnSign.setPrefWidth(Region.USE_COMPUTED_SIZE);
btnSign.setMinWidth(javafx.scene.layout.Region.USE_PREF_SIZE);
btnSign.setDefaultButton(true);
btnSign.setOnAction(e -> handleSign());
@@ -318,9 +317,10 @@ public final class PdfCertificateSignDialog {
root.getChildren().addAll(header, summaryBox, certSection, footer);
Scene scene = new Scene(root, 720, 500);
Scene scene = new Scene(root);
ThemeManager.applyTheme(scene);
stage.setScene(scene);
stage.sizeToScene();
updatePinFieldVisibility();
}
@@ -270,14 +270,13 @@ public final class PdfSignDialog {
btnCancel = new Button("Cancelar");
btnCancel.getStyleClass().addAll("btn-ghost", "btn-dialog");
btnCancel.setMinWidth(110);
btnCancel.setMinWidth(Region.USE_PREF_SIZE);
btnCancel.setOnAction(e -> stage.close());
btnNextToCert = new Button("Avançar", SvgIcons.arrowRightIcon(12));
btnNextToCert.setContentDisplay(javafx.scene.control.ContentDisplay.RIGHT);
btnNextToCert.getStyleClass().addAll("btn-primary", "btn-dialog-wide");
btnNextToCert.setMinWidth(240);
btnNextToCert.setPrefWidth(250);
btnNextToCert.setMinWidth(Region.USE_PREF_SIZE);
btnNextToCert.setDefaultButton(true);
btnNextToCert.setOnAction(e -> handleAdvanceToCertificate());
@@ -291,6 +290,7 @@ public final class PdfSignDialog {
Scene scene = new Scene(root, 1020, 680);
ThemeManager.applyTheme(scene);
stage.setScene(scene);
stage.sizeToScene();
updateSealPreview();
}
@@ -429,6 +429,7 @@ public final class PdfSignDialog {
btnPrevPage = new Button("◀");
btnPrevPage.getStyleClass().addAll("btn-secondary", "btn-compact");
btnPrevPage.setMinWidth(Region.USE_PREF_SIZE);
btnPrevPage.setTooltip(new Tooltip("Página Anterior"));
btnPrevPage.setDisable(true);
btnPrevPage.setOnAction(e -> navigatePage(-1));
@@ -438,6 +439,7 @@ public final class PdfSignDialog {
btnNextPage = new Button("▶");
btnNextPage.getStyleClass().addAll("btn-secondary", "btn-compact");
btnNextPage.setMinWidth(Region.USE_PREF_SIZE);
btnNextPage.setTooltip(new Tooltip("Próxima Página"));
btnNextPage.setDisable(true);
btnNextPage.setOnAction(e -> navigatePage(1));
@@ -456,6 +458,7 @@ public final class PdfSignDialog {
btnZoomOut = new Button();
btnZoomOut.setGraphic(SvgIcons.zoomOutIcon(13));
btnZoomOut.getStyleClass().addAll("btn-secondary", "btn-compact");
btnZoomOut.setMinWidth(Region.USE_PREF_SIZE);
btnZoomOut.setTooltip(new Tooltip("Diminuir Zoom"));
btnZoomOut.setOnAction(e -> adjustZoom(-ZOOM_STEP));
@@ -465,12 +468,14 @@ public final class PdfSignDialog {
btnZoomIn = new Button();
btnZoomIn.setGraphic(SvgIcons.zoomInIcon(13));
btnZoomIn.getStyleClass().addAll("btn-secondary", "btn-compact");
btnZoomIn.setMinWidth(Region.USE_PREF_SIZE);
btnZoomIn.setTooltip(new Tooltip("Aumentar Zoom"));
btnZoomIn.setOnAction(e -> adjustZoom(ZOOM_STEP));
btnZoomFit = new Button("Ajustar");
btnZoomFit.setGraphic(SvgIcons.zoomFitIcon(12));
btnZoomFit.getStyleClass().addAll("btn-secondary", "btn-compact");
btnZoomFit.setMinWidth(Region.USE_PREF_SIZE);
btnZoomFit.setTooltip(new Tooltip("Ajustar à janela"));
btnZoomFit.setOnAction(e -> setZoom(1.0));
@@ -483,6 +488,7 @@ public final class PdfSignDialog {
btnToggleResize = new Button(" Redimensionar", SvgIcons.zoomFitIcon(13));
btnToggleResize.getStyleClass().addAll("btn-secondary", "btn-compact");
btnToggleResize.setMinWidth(Region.USE_PREF_SIZE);
btnToggleResize.setTooltip(new Tooltip("Ativar/desativar alça interativa para alterar o tamanho do selo"));
btnToggleResize.setOnAction(e -> toggleResizeMode());
@@ -491,6 +497,7 @@ public final class PdfSignDialog {
btnResetSealScale = new Button(" 100%", SvgIcons.refreshIcon(12));
btnResetSealScale.getStyleClass().addAll("btn-secondary", "btn-compact");
btnResetSealScale.setMinWidth(Region.USE_PREF_SIZE);
btnResetSealScale.setTooltip(new Tooltip("Restaurar tamanho padrão original (100%)"));
btnResetSealScale.setVisible(false);
btnResetSealScale.setOnAction(e -> applySealScale(1.0));
@@ -383,24 +383,33 @@ public final class SealDesignerDialog {
footer.setAlignment(Pos.CENTER_RIGHT);
footer.setPadding(new Insets(6, 0, 0, 0));
Region spacer = new Region();
HBox.setHgrow(spacer, Priority.ALWAYS);
Button btnCancel = new Button("Cancelar");
btnCancel.getStyleClass().add("btn-secondary");
btnCancel.getStyleClass().add("btn-ghost");
btnCancel.setMinWidth(Region.USE_PREF_SIZE);
btnCancel.setPrefHeight(34);
btnCancel.setOnAction(e -> stage.close());
Button btnInstall = new Button("💾 Instalar Selo no Sistema");
btnInstall.getStyleClass().add("btn-primary");
btnInstall.setMinWidth(Region.USE_PREF_SIZE);
btnInstall.setPrefHeight(34);
btnInstall.setDefaultButton(true);
btnInstall.setOnAction(e -> handleInstallSeal());
footer.getChildren().addAll(btnCancel, btnInstall);
btnImport.setMinWidth(Region.USE_PREF_SIZE);
btnExport.setMinWidth(Region.USE_PREF_SIZE);
footer.getChildren().addAll(spacer, btnCancel, btnInstall);
root.getChildren().addAll(header, mainSplit, footer);
Scene scene = new Scene(root, 880, 580);
ThemeManager.applyTheme(scene);
stage.setScene(scene);
stage.sizeToScene();
}
private void updatePreview() {
@@ -640,4 +649,8 @@ public final class SealDesignerDialog {
stage.centerOnScreen();
stage.show();
}
public Stage getStage() {
return this.stage;
}
}
@@ -222,9 +222,8 @@ public final class SealManagementDialog {
footer.setAlignment(Pos.CENTER_RIGHT);
Button btnClose = new Button(" Fechar", SvgIcons.closeIcon(13));
btnClose.getStyleClass().addAll("btn-secondary", "btn-dialog");
btnClose.setPrefWidth(110);
btnClose.setMinWidth(110);
btnClose.getStyleClass().addAll("btn-ghost", "btn-dialog");
btnClose.setMinWidth(javafx.scene.layout.Region.USE_PREF_SIZE);
btnClose.setOnAction(e -> stage.close());
footer.getChildren().add(btnClose);
@@ -234,6 +233,7 @@ public final class SealManagementDialog {
Scene scene = new Scene(root, 880, 560);
ThemeManager.applyTheme(scene);
stage.setScene(scene);
stage.sizeToScene();
}
private void refreshSealsList() {
@@ -441,6 +441,10 @@ public final class SealManagementDialog {
stage.showAndWait();
}
public Stage getStage() {
return this.stage;
}
/**
* Célula customizada para a listagem visual dos selos.
*/
@@ -66,7 +66,6 @@ public class SignaturePromptDialog {
VBox root = new VBox(16);
root.getStyleClass().add("dialog-container");
root.setPadding(new Insets(20, 24, 20, 24));
root.setPrefWidth(560);
HBox headerBox = new HBox(14);
headerBox.setAlignment(Pos.CENTER_LEFT);
@@ -240,14 +239,19 @@ public class SignaturePromptDialog {
actionsRow.setPadding(new Insets(4, 0, 0, 0));
Button btnCancel = new Button("Cancelar");
btnCancel.getStyleClass().add("btn-cancel");
btnCancel.getStyleClass().addAll("btn-ghost", "btn-dialog");
btnCancel.setMinWidth(javafx.scene.layout.Region.USE_PREF_SIZE);
btnCancel.setOnAction(e -> {
approvalFuture.complete(false);
stage.close();
});
HBox spacer = new HBox();
HBox.setHgrow(spacer, Priority.ALWAYS);
Button btnConfirm = new Button(isAuthentication ? "Confirmar e Entrar" : "Confirmar e Assinar");
btnConfirm.getStyleClass().add("btn-primary");
btnConfirm.getStyleClass().addAll("btn-primary", "btn-dialog");
btnConfirm.setMinWidth(javafx.scene.layout.Region.USE_PREF_SIZE);
btnConfirm.setDefaultButton(true);
btnConfirm.setOnAction(e -> {
if (isA3 && !isWindowsStore) {
@@ -277,7 +281,7 @@ public class SignaturePromptDialog {
stage.close();
});
actionsRow.getChildren().addAll(btnCancel, btnConfirm);
actionsRow.getChildren().addAll(btnCancel, spacer, btnConfirm);
if (isA3) {
root.getChildren().addAll(headerBox, detailsBox, pinContainer, validationLabel, actionsRow);
@@ -335,4 +339,8 @@ public class SignaturePromptDialog {
}
return sb.toString();
}
public Stage getStage() {
return this.stage;
}
}
@@ -19,6 +19,7 @@ import javafx.scene.control.TextField;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.stage.Modality;
@@ -120,6 +121,7 @@ public final class SignatureValidationDialog {
Button btnBrowseSig = new Button("Procurar...");
btnBrowseSig.getStyleClass().add("btn-secondary");
btnBrowseSig.setMinWidth(Region.USE_PREF_SIZE);
btnBrowseSig.setOnAction(e -> handleBrowseSig());
sigRow.getChildren().addAll(txtSigPath, btnBrowseSig);
@@ -139,6 +141,7 @@ public final class SignatureValidationDialog {
Button btnBrowseDoc = new Button("Procurar...");
btnBrowseDoc.getStyleClass().add("btn-secondary");
btnBrowseDoc.setMinWidth(Region.USE_PREF_SIZE);
btnBrowseDoc.setOnAction(e -> handleBrowseDoc());
docRow.getChildren().addAll(txtDocPath, btnBrowseDoc);
@@ -161,28 +164,35 @@ public final class SignatureValidationDialog {
btnSaveExtracted = new Button("Salvar Conteúdo Extraído...");
btnSaveExtracted.getStyleClass().add("btn-secondary");
btnSaveExtracted.setMinWidth(Region.USE_PREF_SIZE);
btnSaveExtracted.setVisible(false);
btnSaveExtracted.setManaged(false);
btnSaveExtracted.setOnAction(e -> handleSaveExtracted());
HBox.setHgrow(btnSaveExtracted, Priority.NEVER);
Region spacer = new Region();
HBox.setHgrow(spacer, Priority.ALWAYS);
Button btnClose = new Button("Fechar");
btnClose.getStyleClass().add("btn-secondary");
btnClose.getStyleClass().add("btn-ghost");
btnClose.setMinWidth(Region.USE_PREF_SIZE);
btnClose.setOnAction(e -> stage.close());
Button btnValidate = new Button("Validar Agora");
btnValidate.getStyleClass().add("btn-primary");
btnValidate.setMinWidth(Region.USE_PREF_SIZE);
btnValidate.setDefaultButton(true);
btnValidate.setOnAction(e -> handleValidate());
footer.getChildren().addAll(btnSaveExtracted, btnClose, btnValidate);
footer.getChildren().addAll(btnSaveExtracted, spacer, btnClose, btnValidate);
root.getChildren().addAll(header, typeBox, sigBox, docBox, scrollResult, footer);
Scene scene = new Scene(root);
ThemeManager.applyTheme(scene);
stage.setScene(scene);
stage.sizeToScene();
updateModeView();
}
@@ -382,4 +392,8 @@ public final class SignatureValidationDialog {
public void show() {
stage.show();
}
public Stage getStage() {
return this.stage;
}
}
@@ -77,9 +77,8 @@ public final class TutorialDialog {
HBox footer = new HBox();
footer.setAlignment(Pos.CENTER_RIGHT);
Button btnClose = new Button(" Entendi", SvgIcons.closeIcon(13));
btnClose.getStyleClass().addAll("btn-secondary", "btn-dialog");
btnClose.setPrefWidth(110);
btnClose.setMinWidth(110);
btnClose.getStyleClass().addAll("btn-ghost", "btn-dialog");
btnClose.setMinWidth(javafx.scene.layout.Region.USE_PREF_SIZE);
btnClose.setOnAction(e -> stage.close());
footer.getChildren().add(btnClose);
@@ -89,6 +88,7 @@ public final class TutorialDialog {
ThemeManager.applyTheme(scene);
stage.setScene(scene);
stage.sizeToScene();
}
private void addStep(VBox container, String title, String description) {
@@ -116,4 +116,8 @@ public final class TutorialDialog {
public void show() {
stage.show();
}
public Stage getStage() {
return this.stage;
}
}
@@ -294,6 +294,7 @@ public final class XmlSignDialog {
btnCancel = new Button("Cancelar");
btnCancel.getStyleClass().addAll("btn-ghost", "btn-dialog");
btnCancel.setMinWidth(Region.USE_PREF_SIZE);
btnCancel.setOnAction(e -> stage.close());
btnSign = new Button("Assinar Documento XML");
@@ -309,6 +310,7 @@ public final class XmlSignDialog {
Scene scene = new Scene(root);
ThemeManager.applyTheme(scene);
stage.setScene(scene);
stage.sizeToScene();
updatePinFieldVisibility();
}
@@ -554,4 +556,8 @@ public final class XmlSignDialog {
stage.show();
stage.toFront();
}
public Stage getStage() {
return this.stage;
}
}
@@ -1,7 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<rect x="3" y="4" width="18" height="16" rx="2.5" fill="none" stroke="currentColor" stroke-width="2"/>
<circle cx="12" cy="10" r="2.5" fill="none" stroke="#0288d1" stroke-width="1.8"/>
<path d="M 10.5 12.2 L 9.5 17 L 12 15.5 L 14.5 17 L 13.5 12.2" fill="none" stroke="#0288d1" stroke-width="1.8" stroke-linejoin="round"/>
<line x1="6" y1="7" x2="8" y2="7" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
<line x1="16" y1="7" x2="18" y2="7" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
<rect x="3.5" y="2.5" width="17" height="19" rx="2.5" fill="none" stroke="currentColor" stroke-width="2"/>
<line x1="7" y1="6.5" x2="13" y2="6.5" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
<line x1="7" y1="9.5" x2="11" y2="9.5" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" opacity="0.6"/>
<circle cx="14.5" cy="14.5" r="3.5" fill="none" stroke="#0288d1" stroke-width="1.8"/>
<path d="M 13 14.5 L 14.2 15.7 L 16.5 13.2" fill="none" stroke="#0288d1" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 625 B

After

Width:  |  Height:  |  Size: 659 B

@@ -1,5 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<circle cx="12" cy="10" r="7.5" fill="none" stroke="#f59e0b" stroke-width="2"/>
<circle cx="12" cy="10" r="4.5" fill="none" stroke="#f59e0b" stroke-width="1.2" stroke-dasharray="2 1.5"/>
<path d="M 9.5 15.5 L 7 21.5 L 12 19 L 17 21.5 L 14.5 15.5" fill="none" stroke="#d97706" stroke-width="1.8" stroke-linejoin="round"/>
<rect x="2.5" y="4.5" width="19" height="15" rx="3" fill="none" stroke="currentColor" stroke-width="2"/>
<path d="M 6 13.5 C 7.5 10 9 10 10.5 13 C 11.5 15 13 11 15 12" fill="none" stroke="#0288d1" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="17.5" cy="8.5" r="1.5" fill="#f59e0b"/>
<line x1="6" y1="8.5" x2="13" y2="8.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" opacity="0.5"/>
<line x1="6" y1="16" x2="18" y2="16" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" opacity="0.4"/>
</svg>

Before

Width:  |  Height:  |  Size: 418 B

After

Width:  |  Height:  |  Size: 654 B

@@ -145,6 +145,7 @@
3. HUB DE AÇÕES E PAINEL LATERAL
========================================================================== */
.button.cyber-action-card,
.cyber-action-card {
-fx-background-color: -fx-color-surface;
-fx-border-color: -fx-color-border;
@@ -160,16 +161,24 @@
-fx-effect: dropshadow(three-pass-box, -fx-color-shadow, 6, 0, 0, 2);
}
.button.cyber-action-card:hover,
.cyber-action-card:hover {
-fx-background-color: -fx-color-surface-hover;
-fx-border-color: -fx-color-primary;
-fx-effect: dropshadow(three-pass-box, -fx-color-shadow-hover, 10, 0, 0, 4);
}
.button.cyber-action-card:pressed,
.cyber-action-card:pressed {
-fx-background-color: -fx-color-surface-active;
}
.button.cyber-action-card:focused,
.cyber-action-card:focused {
-fx-border-color: -fx-color-focus;
-fx-border-width: 1.5px;
}
.cyber-action-text {
-fx-font-size: 13px;
-fx-font-weight: bold;
@@ -187,6 +196,7 @@
-fx-effect: dropshadow(three-pass-box, -fx-color-shadow, 4, 0, 0, 1);
}
.button.cyber-side-card,
.cyber-side-card {
-fx-background-color: transparent;
-fx-border-color: transparent;
@@ -196,18 +206,29 @@
-fx-padding: 6px 10px;
-fx-alignment: CENTER_LEFT;
-fx-cursor: hand;
-fx-pref-height: 40px;
-fx-min-height: 40px;
-fx-max-width: Infinity;
}
.button.cyber-side-card:hover,
.cyber-side-card:hover {
-fx-background-color: -fx-color-surface-hover;
-fx-border-color: -fx-color-border-subtle;
}
.button.cyber-side-card:pressed,
.cyber-side-card:pressed {
-fx-background-color: -fx-color-surface-active;
}
.button.cyber-side-card:focused,
.cyber-side-card:focused {
-fx-background-color: -fx-color-surface-hover;
-fx-border-color: -fx-color-focus;
-fx-border-width: 1.5px;
}
.cyber-side-text {
-fx-font-size: 13px;
-fx-text-fill: -fx-color-text;
@@ -522,7 +543,7 @@
-fx-background-color: transparent;
-fx-border-color: transparent;
-fx-border-width: 1px;
-fx-text-fill: -fx-color-text;
-fx-text-fill: -fx-color-text-muted;
-fx-font-weight: 500;
}
@@ -542,7 +563,8 @@
.btn-ghost:focused,
.btn-toolbar:focused,
.btn-cancel:focused {
-fx-border-color: -fx-color-focus;
-fx-background-color: -fx-color-surface-hover;
-fx-border-color: -fx-color-border-subtle;
-fx-border-width: 1.5px;
}
@@ -28,7 +28,9 @@ import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.control.Button;
import javafx.scene.transform.Transform;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.image.PixelReader;
@@ -108,13 +110,33 @@ public class UiPreviewGenerator extends Application {
private void captureHubScreenshots(Stage stage) throws Exception {
MainAppView appView = new MainAppView(stage);
// 1. Resolução padrão 780x500
stage.setWidth(780);
stage.setHeight(500);
stage.show();
stage.getScene().getRoot().applyCss();
stage.getScene().getRoot().layout();
saveNodeSnapshot(stage.getScene(), new File(OUTPUT_DIR, "01_hub.png"));
saveNodeSnapshot(stage.getScene(), new File(OUTPUT_DIR, "01_hub_780x500.png"));
saveNodeSnapshot(stage.getScene(), new File(OUTPUT_DIR, "01_hub_claro.png"));
saveNodeSnapshot(stage.getScene(), new File(OUTPUT_DIR, "01_layout_claro.png"));
// 2. Escala 150% (High-DPI / Zoom 1.5x)
saveNodeSnapshotScaled(stage.getScene(), new File(OUTPUT_DIR, "01_hub_scale150.png"), 1.5);
// 3. Resolução expandida 1024x768
stage.setWidth(1024);
stage.setHeight(768);
stage.getScene().getRoot().applyCss();
stage.getScene().getRoot().layout();
saveNodeSnapshot(stage.getScene(), new File(OUTPUT_DIR, "01_hub_1024x768.png"));
// Restaura tamanho padrão para os diálogos subsequentes
stage.setWidth(780);
stage.setHeight(500);
}
private void captureDiagnosticsScreenshots(Stage stage) throws Exception {
@@ -551,7 +573,15 @@ public class UiPreviewGenerator extends Application {
}
private static void saveNodeSnapshot(Scene scene, File targetFile) throws Exception {
WritableImage image = scene.snapshot(null);
saveNodeSnapshotScaled(scene, targetFile, 1.0);
}
private static void saveNodeSnapshotScaled(Scene scene, File targetFile, double scale) throws Exception {
SnapshotParameters params = new SnapshotParameters();
if (scale != 1.0) {
params.setTransform(Transform.scale(scale, scale));
}
WritableImage image = scene.getRoot().snapshot(params, null);
int width = (int) image.getWidth();
int height = (int) image.getHeight();
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
@@ -562,6 +592,6 @@ public class UiPreviewGenerator extends Application {
}
}
ImageIO.write(bufferedImage, "png", targetFile);
System.out.println("Screenshot gerada: " + targetFile.getName());
System.out.println("Screenshot gerada: " + targetFile.getName() + " (" + width + "x" + height + ")");
}
}
@@ -0,0 +1,406 @@
package br.com.cybercore.signer.ui.view;
import br.com.cybercore.signer.core.crypto.SigningService;
import br.com.cybercore.signer.core.domain.CertificateStatus;
import br.com.cybercore.signer.core.domain.CertificateType;
import br.com.cybercore.signer.core.domain.ManagedCertificate;
import br.com.cybercore.signer.core.domain.SigningContext;
import br.com.cybercore.signer.core.pdf.PdfSigningService;
import br.com.cybercore.signer.core.pdf.seal.CpfDisplayMode;
import br.com.cybercore.signer.core.pdf.seal.PdfSealThemeRegistry;
import br.com.cybercore.signer.core.provider.CertificateManager;
import br.com.cybercore.signer.ui.components.SvgIcons;
import javafx.application.Platform;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Stage;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Teste automatizado de integridade de layout para telas e diálogos do CyberCore Signer.
* Garante que nenhum botão tenha seu texto ou área comprimida/truncada (largura ou altura menor que pref).
* Valida também as dimensões mínimas dos cartões do Hub (min 68px) e da lista lateral (min 40px).
*/
class ButtonLayoutIntegrityTest {
private static boolean javaFxAvailable = false;
@BeforeAll
static void initJavaFx() {
CountDownLatch latch = new CountDownLatch(1);
try {
Platform.startup(() -> {
javaFxAvailable = true;
latch.countDown();
});
if (!latch.await(5, TimeUnit.SECONDS)) {
javaFxAvailable = false;
}
} catch (Throwable t) {
if (t instanceof IllegalStateException && t.getMessage() != null
&& t.getMessage().contains("Toolkit already initialized")) {
javaFxAvailable = true;
} else {
javaFxAvailable = false;
}
}
}
private void runOnFxThread(ThrowingRunnable action) throws Throwable {
org.junit.jupiter.api.Assumptions.assumeTrue(javaFxAvailable, "Ambiente gráfico JavaFX (X11/Xvfb) não disponível.");
CountDownLatch latch = new CountDownLatch(1);
AtomicReference<Throwable> error = new AtomicReference<>();
Platform.runLater(() -> {
try {
action.run();
} catch (Throwable t) {
error.set(t);
} finally {
latch.countDown();
}
});
assertThat(latch.await(8, TimeUnit.SECONDS)).isTrue();
if (error.get() != null) {
throw error.get();
}
}
@FunctionalInterface
interface ThrowingRunnable {
void run() throws Throwable;
}
private void layoutAndAssert(Stage stage, double width, double height, String screenName) {
Scene scene = stage.getScene();
if (width > 0 && height > 0) {
stage.setWidth(width);
stage.setHeight(height);
}
Parent root = scene.getRoot();
root.applyCss();
if (width > 0 && height > 0) {
root.resizeRelocate(0, 0, width, height);
}
root.layout();
List<Button> buttons = new ArrayList<>();
findButtons(root, buttons);
for (Button b : buttons) {
if (!b.isVisible() || !b.isManaged()) {
continue;
}
double w = b.getWidth();
double h = b.getHeight();
double prefW = b.prefWidth(-1);
double prefH = b.prefHeight(-1);
assertThat(w)
.withFailMessage("Botão '%s' na tela [%s] teve largura comprimida: w=%.1f < prefW=%.1f",
b.getText(), screenName, w, prefW)
.isGreaterThanOrEqualTo(prefW - 0.5);
assertThat(h)
.withFailMessage("Botão '%s' na tela [%s] teve altura comprimida: h=%.1f < prefH=%.1f",
b.getText(), screenName, h, prefH)
.isGreaterThanOrEqualTo(prefH - 0.5);
if (b.getStyleClass().contains("cyber-action-card")) {
assertThat(h)
.withFailMessage("Cartão do Hub '%s' na tela [%s] teve altura menor que 68px: h=%.1f",
b.getText(), screenName, h)
.isGreaterThanOrEqualTo(68.0 - 0.5);
}
if (b.getStyleClass().contains("cyber-side-card")) {
assertThat(h)
.withFailMessage("Item lateral do Hub '%s' na tela [%s] teve altura menor que 40px: h=%.1f",
b.getText(), screenName, h)
.isGreaterThanOrEqualTo(40.0 - 0.5);
}
}
}
private void findButtons(Node node, List<Button> accumulator) {
if (node instanceof Button btn) {
accumulator.add(btn);
}
if (node instanceof Parent parent) {
for (Node child : parent.getChildrenUnmodifiable()) {
findButtons(child, accumulator);
}
}
}
private ManagedCertificate createSampleCertificate() {
return new ManagedCertificate(
"cert-test-id",
"JOAO DA SILVA:12345678900",
CertificateType.A1,
CertificateStatus.AVAILABLE,
"CN=JOAO DA SILVA:12345678900, OU=Autenticado por AR, O=ICP-Brasil, C=BR",
"CN=AC SERPRO RFB v5, O=ICP-Brasil, C=BR",
"1A2B3C4D5E",
"11223344556677889900",
"AABBCCDDEEFF00112233445566778899",
Instant.now().minus(30, ChronoUnit.DAYS),
Instant.now().plus(330, ChronoUnit.DAYS),
"RSA",
2048,
"JOAO DA SILVA:12345678900",
"12345678900",
null,
"SunJSSE",
null
);
}
private static File getOrCreateSamplePdf() throws Exception {
File pdf = new File("target/test-sample.pdf");
if (!pdf.exists()) {
if (pdf.getParentFile() != null) {
pdf.getParentFile().mkdirs();
}
try (org.apache.pdfbox.pdmodel.PDDocument document = new org.apache.pdfbox.pdmodel.PDDocument()) {
org.apache.pdfbox.pdmodel.PDPage page = new org.apache.pdfbox.pdmodel.PDPage();
document.addPage(page);
try (org.apache.pdfbox.pdmodel.PDPageContentStream cs = new org.apache.pdfbox.pdmodel.PDPageContentStream(document, page)) {
cs.beginText();
cs.setFont(new org.apache.pdfbox.pdmodel.font.PDType1Font(org.apache.pdfbox.pdmodel.font.Standard14Fonts.FontName.HELVETICA_BOLD), 14);
cs.newLineAtOffset(50, 700);
cs.showText("CyberCore Signer Test PDF");
cs.endText();
}
document.save(pdf);
}
}
return pdf;
}
@Test
@DisplayName("Hub Principal (MainAppView): nenhum botão deve truncar e os cartões devem ter altura >= 68px")
void testMainAppViewButtons() throws Throwable {
runOnFxThread(() -> {
Stage stage = new Stage();
MainAppView view = new MainAppView(stage);
layoutAndAssert(stage, 780, 500, "MainAppView 780x500");
layoutAndAssert(stage, 1024, 768, "MainAppView 1024x768");
});
}
@Test
@DisplayName("ExitConfirmationDialog: botões Cancelar, Encerrar e Minimizar com tamanho preferencial")
void testExitConfirmationDialogButtons() throws Throwable {
runOnFxThread(() -> {
ExitConfirmationDialog dialog = new ExitConfirmationDialog(null);
layoutAndAssert(dialog.getStage(), 480, 220, "ExitConfirmationDialog");
});
}
@Test
@DisplayName("ApplicationApprovalDialog: botões com tamanho preferencial e sem truncamento")
void testApplicationApprovalDialogButtons() throws Throwable {
runOnFxThread(() -> {
Stage stage = new Stage();
ApplicationApprovalDialog dialog = new ApplicationApprovalDialog(
stage,
"https://contratos.empresa.com.br",
"Sistema de Contratos Online",
"app-test-id"
);
layoutAndAssert(dialog.getStage(), 520, 360, "ApplicationApprovalDialog");
});
}
@Test
@DisplayName("A1PasswordDialog: botões Cancelar e Desbloquear com tamanho preferencial")
void testA1PasswordDialogButtons() throws Throwable {
runOnFxThread(() -> {
A1PasswordDialog dialog = new A1PasswordDialog(null, "certificado-empresa.pfx");
layoutAndAssert(dialog.getStage(), 460, 260, "A1PasswordDialog");
});
}
@Test
@DisplayName("SignaturePromptDialog: botões Cancelar e Confirmar com tamanho preferencial")
void testSignaturePromptDialogButtons() throws Throwable {
runOnFxThread(() -> {
ManagedCertificate cert = createSampleCertificate();
SigningContext ctx = new SigningContext(
"req-1234",
"app-web",
new byte[32],
"SHA256withRSA",
null,
Instant.now().plusSeconds(60)
);
SignaturePromptDialog dialog = new SignaturePromptDialog(
null,
"Portal Financeiro",
"https://financeiro.gov.br",
cert,
ctx,
"Ordem_Pagamento_2026.pdf",
"PDF",
false
);
layoutAndAssert(dialog.getStage(), 560, 420, "SignaturePromptDialog");
});
}
@Test
@DisplayName("CertificatesManagerDialog: botões de ação e fechamento com tamanho preferencial")
void testCertificatesManagerDialogButtons() throws Throwable {
runOnFxThread(() -> {
CertificateManager certManager = CertificateManager.createDefault();
CertificatesManagerDialog dialog = new CertificatesManagerDialog(null, certManager);
layoutAndAssert(dialog.getStage(), 760, 520, "CertificatesManagerDialog");
});
}
@Test
@DisplayName("CertificateDetailsDialog: botão Fechar com tamanho preferencial")
void testCertificateDetailsDialogButtons() throws Throwable {
runOnFxThread(() -> {
ManagedCertificate cert = createSampleCertificate();
CertificateDetailsDialog dialog = new CertificateDetailsDialog(null, cert);
layoutAndAssert(dialog.getStage(), 620, 500, "CertificateDetailsDialog");
});
}
@Test
@DisplayName("FileSignDialog: botões com tamanho preferencial")
void testFileSignDialogButtons() throws Throwable {
runOnFxThread(() -> {
CertificateManager certManager = CertificateManager.createDefault();
SigningService signingService = new SigningService(certManager);
FileSignDialog dialog = new FileSignDialog(
null,
"Assinar Arquivo",
"*.*",
SvgIcons.fileIcon(),
certManager,
signingService
);
layoutAndAssert(dialog.getStage(), 720, 500, "FileSignDialog");
});
}
@Test
@DisplayName("LogsViewerDialog: botões Limpar, Exportar e Fechar com tamanho preferencial")
void testLogsViewerDialogButtons() throws Throwable {
runOnFxThread(() -> {
LogsViewerDialog dialog = new LogsViewerDialog(null);
layoutAndAssert(dialog.getStage(), 800, 520, "LogsViewerDialog");
});
}
@Test
@DisplayName("TutorialDialog: botões de navegação e fechar com tamanho preferencial")
void testTutorialDialogButtons() throws Throwable {
runOnFxThread(() -> {
TutorialDialog dialog = new TutorialDialog(null);
layoutAndAssert(dialog.getStage(), 640, 480, "TutorialDialog");
});
}
@Test
@DisplayName("XmlSignDialog: botões com tamanho preferencial")
void testXmlSignDialogButtons() throws Throwable {
runOnFxThread(() -> {
CertificateManager certManager = CertificateManager.createDefault();
XmlSignDialog dialog = new XmlSignDialog(null, certManager);
layoutAndAssert(dialog.getStage(), 720, 500, "XmlSignDialog");
});
}
@Test
@DisplayName("BatchSigningDialog: botões com tamanho preferencial")
void testBatchSigningDialogButtons() throws Throwable {
runOnFxThread(() -> {
CertificateManager certManager = CertificateManager.createDefault();
SigningService signingService = new SigningService(certManager);
BatchSigningDialog dialog = new BatchSigningDialog(null, certManager, signingService);
layoutAndAssert(dialog.getStage(), 760, 520, "BatchSigningDialog");
});
}
@Test
@DisplayName("SealManagementDialog e SealDesignerDialog: botões com tamanho preferencial")
void testSealDialogsButtons() throws Throwable {
runOnFxThread(() -> {
SealManagementDialog sealMgmt = new SealManagementDialog(null);
layoutAndAssert(sealMgmt.getStage(), 700, 480, "SealManagementDialog");
SealDesignerDialog designer = new SealDesignerDialog(null, PdfSealThemeRegistry.getDefaultTheme(), saved -> {});
layoutAndAssert(designer.getStage(), 880, 580, "SealDesignerDialog");
});
}
@Test
@DisplayName("SignatureValidationDialog: botões com tamanho preferencial")
void testSignatureValidationDialogButtons() throws Throwable {
runOnFxThread(() -> {
SignatureValidationDialog dialog = new SignatureValidationDialog(null);
layoutAndAssert(dialog.getStage(), 680, 520, "SignatureValidationDialog");
});
}
@Test
@DisplayName("PdfSignDialog e PdfCertificateSignDialog: botões com tamanho preferencial")
void testPdfDialogsButtons() throws Throwable {
runOnFxThread(() -> {
File samplePdf = getOrCreateSamplePdf();
CertificateManager certManager = CertificateManager.createDefault();
PdfSigningService pdfSigningService = new PdfSigningService(certManager);
PdfSignDialog pdfSignDialog = new PdfSignDialog(null, certManager, samplePdf);
layoutAndAssert(pdfSignDialog.getStage(), 980, 680, "PdfSignDialog");
PdfCertificateSignDialog.SealConfig config = new PdfCertificateSignDialog.SealConfig(
true,
PdfSealThemeRegistry.getDefaultTheme(),
CpfDisplayMode.MASKED,
true,
"Assinado digitalmente",
PdfSignDialog.PositionOption.BOTTOM_RIGHT,
PdfSignDialog.PageOption.LAST_PAGE,
false,
null,
null,
null,
"ICP-Brasil",
"Brasília, DF",
1.0
);
PdfCertificateSignDialog certSignDialog = new PdfCertificateSignDialog(
null,
certManager,
pdfSigningService,
samplePdf,
config,
"Selo Padrão ICP-Brasil"
);
layoutAndAssert(certSignDialog.getStage(), 760, 520, "PdfCertificateSignDialog");
});
}
}