/*
SPDX-License-Identifier: Apache-2.0
*/
package spdxedit.license;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.*;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.util.StringConverter;
import org.apache.commons.lang3.StringUtils;
import org.spdx.rdfparser.InvalidSPDXAnalysisException;
import org.spdx.rdfparser.SpdxDocumentContainer;
import org.spdx.rdfparser.license.*;
import org.spdx.rdfparser.model.SpdxDocument;
import org.spdx.rdfparser.model.SpdxFile;
import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.Objects;
import java.util.ResourceBundle;
import java.util.concurrent.Callable;
import java.util.function.Consumer;
import java.util.stream.Collectors;
public class LicenseEditControl {
private SpdxDocumentContainer documentContainer;
private SpdxFile file;
private AnyLicenseInfo initialValue = new SpdxNoAssertionLicense();
private boolean showExtractLicenseButton;
@FXML
private ResourceBundle resources;
@FXML
private URL location;
@FXML
private RadioButton rdoNone;
@FXML
private RadioButton rdoNoAssert;
@FXML
private RadioButton rdoStandard;
@FXML
private ChoiceBox<String> chcListedLicense;
@FXML
private ChoiceBox<ExtractedLicenseInfo> chcExtractedLicenses;
@FXML
private RadioButton rdoExtracted;
@FXML
private Button btnNewFromFile;
private Consumer<AnyLicenseInfo> onLicenseChange;
@FXML
void handleBtnNewFromFileClick(MouseEvent event) {
FileLicenseEditor.extractLicenseFromFile(file, documentContainer);
refreshExtractedLicenses();
}
/**
* Creates a new control without an exstract license button.
* @param documentContainer
*/
public LicenseEditControl(SpdxDocumentContainer documentContainer){
this(documentContainer, null, false);
}
/**
*
* @param documentContainer
* @param file File from which to extract the license if Extract License button is clicked.
* @param showExtractLicenseButton
*/
public LicenseEditControl(SpdxDocumentContainer documentContainer, SpdxFile file, boolean showExtractLicenseButton) {
this.showExtractLicenseButton = showExtractLicenseButton;
this.documentContainer = documentContainer;
this.file = file;
}
@FXML
void initialize() {
assert rdoNone != null : "fx:id=\"rdoNone\" was not injected: check your FXML file 'LicenseEditControl.fxml'.";
assert rdoNoAssert != null : "fx:id=\"rdoNoAssert\" was not injected: check your FXML file 'LicenseEditControl.fxml'.";
assert rdoStandard != null : "fx:id=\"rdoStandard\" was not injected: check your FXML file 'LicenseEditControl.fxml'.";
assert chcListedLicense != null : "fx:id=\"chcListedLicense\" was not injected: check your FXML file 'LicenseEditControl.fxml'.";
assert chcExtractedLicenses != null : "fx:id=\"chcExtractedLicenses\" was not injected: check your FXML file 'LicenseEditControl.fxml'.";
assert rdoExtracted != null : "fx:id=\"rdoExtracted\" was not injected: check your FXML file 'LicenseEditControl.fxml'.";
assert btnNewFromFile != null : "fx:id=\"btnNewFromFile\" was not injected: check your FXML file 'LicenseEditControl.fxml'.";
//Make radio buttons mutually exclusive
ToggleGroup licenseTypeGroup = new ToggleGroup();
rdoExtracted.setToggleGroup(licenseTypeGroup);
rdoStandard.setToggleGroup(licenseTypeGroup);
rdoNone.setToggleGroup(licenseTypeGroup);
rdoNoAssert.setToggleGroup(licenseTypeGroup);
//Choice boxes should disable when their respective radio buttons are untoggled.
rdoStandard.selectedProperty().addListener((observable, oldValue, newValue) -> chcListedLicense.setDisable(!newValue));
rdoExtracted.selectedProperty().addListener((observable, oldValue, newValue) -> chcExtractedLicenses.setDisable(!newValue));
chcListedLicense.getItems().addAll(Arrays.stream(ListedLicenses.getListedLicenses().getSpdxListedLicenseIds()).sorted().collect(Collectors.toList()));
chcExtractedLicenses.setConverter(new StringConverter<ExtractedLicenseInfo>() {
@Override
public String toString(ExtractedLicenseInfo object) {
return object.getName();
}
@Override
public ExtractedLicenseInfo fromString(String string) {
return Arrays.stream(documentContainer.getExtractedLicenseInfos()).filter(license -> StringUtils.equals(license.getName(), string)).findAny().get();
}
});
btnNewFromFile.setVisible(showExtractLicenseButton);
//Apply the initial value
if (this.initialValue instanceof SpdxListedLicense) {
chcListedLicense.setValue(((SpdxListedLicense) initialValue).getLicenseId());
chcListedLicense.setDisable(false);
rdoStandard.selectedProperty().setValue(true);
} else if (initialValue instanceof ExtractedLicenseInfo) {
refreshExtractedLicenses();
chcExtractedLicenses.setValue((ExtractedLicenseInfo) initialValue);
chcExtractedLicenses.setDisable(false);
rdoExtracted.selectedProperty().setValue(true);
} else if (initialValue instanceof SpdxNoAssertionLicense) {
rdoNoAssert.selectedProperty().setValue(true);
} else if (initialValue instanceof SpdxNoneLicense) {
rdoNone.selectedProperty().setValue(true);
} else {
new Alert(Alert.AlertType.ERROR, "Unsupported license type: " + initialValue.getClass().getSimpleName() + ".", ButtonType.OK);
}
//Listen for change events
licenseTypeGroup.selectedToggleProperty().addListener((observable1, oldValue1, newValue1) -> {hanldLicenseChangeEvent();});
chcExtractedLicenses.valueProperty().addListener((observable, oldValue, newValue) -> {hanldLicenseChangeEvent();});
chcListedLicense.valueProperty().addListener((observable, oldValue, newValue) -> {hanldLicenseChangeEvent();});
}
private void refreshExtractedLicenses(){
chcExtractedLicenses.getItems().clear();
chcExtractedLicenses.getItems().addAll(Arrays.stream(documentContainer.getExtractedLicenseInfos()).collect(Collectors.toList()));
}
/**
* Sets the initial value of the control. Has no impact if called after the UI is initialized.
* Must not be null.
*
* @param value
*/
public void setInitialValue(AnyLicenseInfo value) {
this.initialValue = Objects.requireNonNull(value);
}
public AnyLicenseInfo getValue() {
AnyLicenseInfo result = null;
if (rdoNoAssert.isSelected()) {
result = new SpdxNoAssertionLicense();
} else if (rdoNone.isSelected()) {
result = new SpdxNoneLicense();
} else if (rdoStandard.isSelected()) {
try {
result = ListedLicenses.getListedLicenses().getListedLicenseById(chcListedLicense.getValue());
} catch (InvalidSPDXAnalysisException e) {
throw new RuntimeException(e);
}
} else if (rdoExtracted.isSelected()) {
result = chcExtractedLicenses.getValue();
}
if (result == null) {
new Alert(Alert.AlertType.ERROR, "Unable to extract selected license", ButtonType.OK);
}
return result;
}
public Pane getUi() {
try {
FXMLLoader loader = new FXMLLoader(LicenseEditControl.class.getResource("/LicenseEdit.fxml"));
loader.setController(this);
Pane pane = loader.load();
return pane;
} catch (IOException ioe) {
throw new RuntimeException("Unable to load scene for License editor dialog");
}
}
public void setOnLicenseChange(Consumer<AnyLicenseInfo> onLicenseChange){
this.onLicenseChange = onLicenseChange;
}
/**
* Catchall handler for all license change events.
*/
private void hanldLicenseChangeEvent(){
if (this.onLicenseChange != null){
this.onLicenseChange.accept(getValue());
}
}
}