mirror of
https://github.com/davidalves04/Trabalho-Pratico-SD.git
synced 2025-12-08 12:33:31 +00:00
183 lines
7.5 KiB
Java
183 lines
7.5 KiB
Java
package sd.dashboard;
|
|
|
|
import javafx.geometry.Insets;
|
|
import javafx.scene.control.ButtonType;
|
|
import javafx.scene.control.ComboBox;
|
|
import javafx.scene.control.Dialog;
|
|
import javafx.scene.control.Label;
|
|
import javafx.scene.control.Separator;
|
|
import javafx.scene.control.Spinner;
|
|
import javafx.scene.layout.GridPane;
|
|
import javafx.scene.layout.VBox;
|
|
import javafx.stage.Modality;
|
|
import javafx.stage.Stage;
|
|
|
|
/**
|
|
* Componente de interface gráfica (GUI) responsável pela parametrização "fine-tuning" da simulação.
|
|
* <p>
|
|
* Esta classe apresenta um diálogo modal que permite ao operador sobrepor (override)
|
|
* as configurações estáticas carregadas do ficheiro {@code .properties} imediatamente
|
|
* antes da execução. Oferece controlo granular sobre:
|
|
* <ul>
|
|
* <li><b>Geração de Carga:</b> Alternância entre modelos estocásticos (Poisson) e determinísticos.</li>
|
|
* <li><b>Temporização:</b> Ajuste da escala de tempo (Time Scale) para visualização vs. performance pura.</li>
|
|
* <li><b>Mix de Veículos:</b> Definição das probabilidades de geração por tipo de agente.</li>
|
|
* </ul>
|
|
*/
|
|
public class ConfigurationDialog {
|
|
|
|
/**
|
|
* Exibe o diálogo de configuração avançada e captura as intenções do utilizador.
|
|
* <p>
|
|
* A interface é construída dinamicamente usando layouts JavaFX ({@link GridPane}, {@link VBox}).
|
|
* Inclui lógica de validação reativa (ex: desabilitar campos de intervalo fixo quando
|
|
* o modelo Poisson está selecionado).
|
|
* *
|
|
|
|
[Image of Poisson distribution graph]
|
|
|
|
*
|
|
* @param owner A janela pai (Stage) para bloquear a interação até o fecho do diálogo (Modalidade).
|
|
* @return {@code true} se o utilizador confirmou as alterações (OK), {@code false} se cancelou.
|
|
*/
|
|
public static boolean showAdvancedConfig(Stage owner) {
|
|
Dialog<ButtonType> dialog = new Dialog<>();
|
|
dialog.initOwner(owner);
|
|
dialog.initModality(Modality.APPLICATION_MODAL);
|
|
dialog.setTitle("Configuração Avançada da Simulação");
|
|
dialog.setHeaderText("Ajustar parâmetros da simulação");
|
|
|
|
// Criar painel de configuração
|
|
VBox content = new VBox(15);
|
|
content.setPadding(new Insets(20));
|
|
|
|
// Seção 1: Parâmetros de Chegada
|
|
Label arrivalHeader = new Label("Parâmetros de Chegada de Veículos");
|
|
arrivalHeader.setStyle("-fx-font-weight: bold; -fx-font-size: 14px;");
|
|
|
|
GridPane arrivalGrid = new GridPane();
|
|
arrivalGrid.setHgap(10);
|
|
arrivalGrid.setVgap(10);
|
|
arrivalGrid.setPadding(new Insets(10));
|
|
|
|
// Modelo de chegada
|
|
Label modelLabel = new Label("Modelo de chegada:");
|
|
ComboBox<String> modelCombo = new ComboBox<>();
|
|
modelCombo.getItems().addAll("POISSON", "FIXED");
|
|
modelCombo.setValue("POISSON");
|
|
arrivalGrid.add(modelLabel, 0, 0);
|
|
arrivalGrid.add(modelCombo, 1, 0);
|
|
|
|
// Taxa de chegada (λ)
|
|
Label rateLabel = new Label("Taxa de chegada (λ) [veículos/s]:");
|
|
Spinner<Double> rateSpinner = new Spinner<>(0.1, 2.0, 0.5, 0.1);
|
|
rateSpinner.setEditable(true);
|
|
rateSpinner.setPrefWidth(100);
|
|
arrivalGrid.add(rateLabel, 0, 1);
|
|
arrivalGrid.add(rateSpinner, 1, 1);
|
|
|
|
// Intervalo fixo (se aplicável)
|
|
Label intervalLabel = new Label("Intervalo fixo [s]:");
|
|
Spinner<Double> intervalSpinner = new Spinner<>(0.5, 10.0, 2.0, 0.5);
|
|
intervalSpinner.setEditable(true);
|
|
intervalSpinner.setPrefWidth(100);
|
|
intervalSpinner.setDisable(true);
|
|
arrivalGrid.add(intervalLabel, 0, 2);
|
|
arrivalGrid.add(intervalSpinner, 1, 2);
|
|
|
|
// Habilitar/desabilitar intervalo baseado no modelo
|
|
modelCombo.setOnAction(e -> {
|
|
boolean isFixed = "FIXED".equals(modelCombo.getValue());
|
|
intervalSpinner.setDisable(!isFixed);
|
|
rateSpinner.setDisable(isFixed);
|
|
});
|
|
|
|
// Seção 2: Parâmetros de Tempo
|
|
Label timeHeader = new Label("Parâmetros de Tempo");
|
|
timeHeader.setStyle("-fx-font-weight: bold; -fx-font-size: 14px;");
|
|
|
|
GridPane timeGrid = new GridPane();
|
|
timeGrid.setHgap(10);
|
|
timeGrid.setVgap(10);
|
|
timeGrid.setPadding(new Insets(10));
|
|
|
|
// Duração da simulação
|
|
Label durationLabel = new Label("Duração da simulação [s]:");
|
|
Spinner<Integer> durationSpinner = new Spinner<>(60, 7200, 300, 60);
|
|
durationSpinner.setEditable(true);
|
|
durationSpinner.setPrefWidth(100);
|
|
timeGrid.add(durationLabel, 0, 0);
|
|
timeGrid.add(durationSpinner, 1, 0);
|
|
|
|
// Escala temporal (para visualização)
|
|
Label scaleLabel = new Label("Escala temporal (0=instantâneo, 1=tempo real):");
|
|
Spinner<Double> scaleSpinner = new Spinner<>(0.0, 1.0, 0.01, 0.01);
|
|
scaleSpinner.setEditable(true);
|
|
scaleSpinner.setPrefWidth(100);
|
|
timeGrid.add(scaleLabel, 0, 1);
|
|
timeGrid.add(scaleSpinner, 1, 1);
|
|
|
|
// Tempo de drenagem
|
|
Label drainLabel = new Label("Tempo de drenagem [s]:");
|
|
Spinner<Integer> drainSpinner = new Spinner<>(0, 300, 60, 10);
|
|
drainSpinner.setEditable(true);
|
|
drainSpinner.setPrefWidth(100);
|
|
timeGrid.add(drainLabel, 0, 2);
|
|
timeGrid.add(drainSpinner, 1, 2);
|
|
|
|
// Seção 3: Distribuição de Tipos de Veículos
|
|
Label vehicleHeader = new Label("Distribuição de Tipos de Veículos");
|
|
vehicleHeader.setStyle("-fx-font-weight: bold; -fx-font-size: 14px;");
|
|
|
|
GridPane vehicleGrid = new GridPane();
|
|
vehicleGrid.setHgap(10);
|
|
vehicleGrid.setVgap(10);
|
|
vehicleGrid.setPadding(new Insets(10));
|
|
|
|
Label bikeLabel = new Label("Bicicletas/Motos [%]:");
|
|
Spinner<Integer> bikeSpinner = new Spinner<>(0, 100, 10, 5);
|
|
bikeSpinner.setEditable(true);
|
|
bikeSpinner.setPrefWidth(100);
|
|
vehicleGrid.add(bikeLabel, 0, 0);
|
|
vehicleGrid.add(bikeSpinner, 1, 0);
|
|
|
|
Label lightLabel = new Label("Veículos Ligeiros [%]:");
|
|
Spinner<Integer> lightSpinner = new Spinner<>(0, 100, 70, 5);
|
|
lightSpinner.setEditable(true);
|
|
lightSpinner.setPrefWidth(100);
|
|
vehicleGrid.add(lightLabel, 0, 1);
|
|
vehicleGrid.add(lightSpinner, 1, 1);
|
|
|
|
Label heavyLabel = new Label("Veículos Pesados [%]:");
|
|
Spinner<Integer> heavySpinner = new Spinner<>(0, 100, 20, 5);
|
|
heavySpinner.setEditable(true);
|
|
heavySpinner.setPrefWidth(100);
|
|
vehicleGrid.add(heavyLabel, 0, 2);
|
|
vehicleGrid.add(heavySpinner, 1, 2);
|
|
|
|
// Nota informativa
|
|
Label noteLabel = new Label("Nota: Estes parâmetros sobrepõem os valores do ficheiro .properties selecionado.\n" +
|
|
"Para usar os valores padrão do ficheiro, deixe em branco ou cancele.");
|
|
noteLabel.setWrapText(true);
|
|
noteLabel.setStyle("-fx-font-size: 11px; -fx-text-fill: #666666;");
|
|
|
|
// Adicionar tudo ao conteúdo
|
|
content.getChildren().addAll(
|
|
arrivalHeader, arrivalGrid,
|
|
new Separator(),
|
|
timeHeader, timeGrid,
|
|
new Separator(),
|
|
vehicleHeader, vehicleGrid,
|
|
new Separator(),
|
|
noteLabel
|
|
);
|
|
|
|
dialog.getDialogPane().setContent(content);
|
|
dialog.getDialogPane().getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);
|
|
|
|
// Mostrar diálogo e processar resultado
|
|
return dialog.showAndWait()
|
|
.map(buttonType -> buttonType == ButtonType.OK)
|
|
.orElse(false);
|
|
}
|
|
} |