From 302bb55fbc2d0269cb56a7bc7112e565a61f7986 Mon Sep 17 00:00:00 2001 From: eparovyshnaya Date: Sun, 18 Feb 2024 19:01:25 +0300 Subject: [PATCH] [#1191] "Import Licenses" wizard should support import from archive ImportLicenseDialog is extended with proper hooks --- .../base/conditions/LicenseConditions.java | 10 +- .../e4/ui/handlers/InspectLicenseHandler.java | 1 + .../licensing/AllConditionsFromLicenses.java | 8 +- .../licensing/BaseLicenseStatusDialog.java | 168 ++++++++++++++++++ .../licensing/FromLocalFileSystem.java | 57 ++++++ .../dialogs/licensing/GoodIntention.java | 21 +-- .../licensing/ImportLicenseDialog.java | 75 +++----- .../licensing/LicenseFilesControl.java | 13 ++ .../jface/dialogs/licensing/LicenseSet.java | 13 +- .../licensing/LicenseStatusDialog.java | 131 ++------------ .../lic/jface/BaseEquinoxPassageUI.java | 110 ++++++++++++ .../passage/lic/jface/EquinoxPassageUI.java | 83 +-------- .../ui/wizards/LicenseIssuedNotification.java | 1 - 13 files changed, 420 insertions(+), 271 deletions(-) create mode 100644 bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/BaseLicenseStatusDialog.java create mode 100644 bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/FromLocalFileSystem.java create mode 100644 bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/LicenseFilesControl.java create mode 100644 bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/jface/BaseEquinoxPassageUI.java diff --git a/bundles/org.eclipse.passage.lic.base/src/org/eclipse/passage/lic/internal/base/conditions/LicenseConditions.java b/bundles/org.eclipse.passage.lic.base/src/org/eclipse/passage/lic/internal/base/conditions/LicenseConditions.java index e06cbdc89..3bcbd714a 100644 --- a/bundles/org.eclipse.passage.lic.base/src/org/eclipse/passage/lic/internal/base/conditions/LicenseConditions.java +++ b/bundles/org.eclipse.passage.lic.base/src/org/eclipse/passage/lic/internal/base/conditions/LicenseConditions.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2021, 2022 ArSysOp + * Copyright (c) 2021, 2024 ArSysOp * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License 2.0 which is available at @@ -9,6 +9,7 @@ * * Contributors: * ArSysOp - initial API and implementation + * ArSysOp - further support *******************************************************************************/ package org.eclipse.passage.lic.internal.base.conditions; @@ -43,12 +44,12 @@ public final class LicenseConditions implements Supplier> owner; - private final Libraries libraries; + private final Optional libraries; public LicenseConditions(// Path file, // Supplier> provider, // - Libraries libraries) { + Optional libraries) { this.file = file; this.owner = provider; this.libraries = libraries; @@ -68,7 +69,8 @@ private ServiceInvocationResult> fromProduct() { } private ServiceInvocationResult> fromLibraries() { - Optional>> request = libraries.licenseReadingServices(); + Optional>> request = libraries + .flatMap(Libraries::licenseReadingServices); if (!request.isPresent()) { return new BaseServiceInvocationResult<>(Collections.emptyList()); } diff --git a/bundles/org.eclipse.passage.lic.e4.ui/src/org/eclipse/passage/lic/internal/e4/ui/handlers/InspectLicenseHandler.java b/bundles/org.eclipse.passage.lic.e4.ui/src/org/eclipse/passage/lic/internal/e4/ui/handlers/InspectLicenseHandler.java index c681c5cff..c2978df4f 100644 --- a/bundles/org.eclipse.passage.lic.e4.ui/src/org/eclipse/passage/lic/internal/e4/ui/handlers/InspectLicenseHandler.java +++ b/bundles/org.eclipse.passage.lic.e4.ui/src/org/eclipse/passage/lic/internal/e4/ui/handlers/InspectLicenseHandler.java @@ -19,6 +19,7 @@ import org.eclipse.passage.lic.jface.EquinoxPassageUI; import org.eclipse.swt.widgets.Shell; +@SuppressWarnings("restriction") public final class InspectLicenseHandler { @Execute diff --git a/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/AllConditionsFromLicenses.java b/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/AllConditionsFromLicenses.java index ac35b7e93..5fb5897c8 100644 --- a/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/AllConditionsFromLicenses.java +++ b/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/AllConditionsFromLicenses.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022 ArSysOp + * Copyright (c) 2022, 2024 ArSysOp * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License 2.0 which is available at @@ -9,6 +9,7 @@ * * Contributors: * ArSysOp - initial API and implementation + * ArSysOp - further support *******************************************************************************/ package org.eclipse.passage.lic.internal.jface.dialogs.licensing; @@ -16,6 +17,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.function.Supplier; import org.eclipse.passage.lic.api.ServiceInvocationResult; @@ -30,10 +32,10 @@ final class AllConditionsFromLicenses implements Supplier>> { private final List licenses; - private final Libraries libraries; + private final Optional libraries; private final LicenseReadingServiceRequest product; - AllConditionsFromLicenses(List licenses, Libraries libraries) { + AllConditionsFromLicenses(List licenses, Optional libraries) { this.licenses = licenses; this.libraries = libraries; this.product = new LicenseReadingServiceRequest(); diff --git a/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/BaseLicenseStatusDialog.java b/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/BaseLicenseStatusDialog.java new file mode 100644 index 000000000..9683b6b40 --- /dev/null +++ b/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/BaseLicenseStatusDialog.java @@ -0,0 +1,168 @@ +/******************************************************************************* + * Copyright (c) 2020, 2024 ArSysOp + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * https://www.eclipse.org/legal/epl-2.0/. + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * ArSysOp - initial API and implementation + * ArSysOp - further support + *******************************************************************************/ +package org.eclipse.passage.lic.internal.jface.dialogs.licensing; + +import java.util.Collection; +import java.util.stream.Collectors; + +import org.eclipse.passage.lic.api.agreements.AgreementToAccept; +import org.eclipse.passage.lic.api.diagnostic.Diagnostic; +import org.eclipse.passage.lic.api.restrictions.ExaminationCertificate; +import org.eclipse.passage.lic.base.diagnostic.DiagnosticExplained; +import org.eclipse.passage.lic.base.diagnostic.NoErrors; +import org.eclipse.passage.lic.base.diagnostic.RequirementStatus; +import org.eclipse.passage.lic.base.diagnostic.RequirementsCoverage; +import org.eclipse.passage.lic.base.restrictions.ExaminationExplained; +import org.eclipse.passage.lic.equinox.ProductContacts; +import org.eclipse.passage.lic.internal.jface.i18n.LicenseStatusDialogMessages; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Shell; + +public abstract class BaseLicenseStatusDialog extends NotificationDialog { + + protected final ExaminationCertificate certificate; + protected final Diagnostic diagnostic; + private GoodIntention intention = new GoodIntention.Nope(); // truly mutable ^:( + private StyledText notice; + + protected BaseLicenseStatusDialog(Shell shell, ExaminationCertificate certificate, Diagnostic diagnostic) { + super(shell); + this.certificate = certificate; + this.diagnostic = diagnostic; + } + + public final GoodIntention goodIntention() { + return intention; + } + + @Override + protected final void configureShell(Shell shell) { + super.configureShell(shell); + shell.setText(LicenseStatusDialogMessages.LicenseStatusDialog_title); + shell.setImage(getDefaultImage()); + shell.setSize(840, 600); + } + + @Override + protected final void buildUI(Composite parent) { + viewer = new HereTable(parent, RequirementStatus.class) // + .withColumn(LicenseStatusDialogMessages.LicenseStatusDialog_column_id, // + 600, RequirementStatus::feature) + .withColumn(LicenseStatusDialogMessages.LicenseStatusDialog_column_status, // + 200, RequirementStatus::status) + .viewer(); + notice = new StyledText(parent, SWT.BORDER | SWT.READ_ONLY); + notice.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + } + + @Override + protected final void inplaceData() { + viewer.setInput(new RequirementsCoverage(certificate).get()); + notice.setText(new ProductContacts().get()); + } + + @Override + protected final void initButtons() { + int button = 1; + new ButtonConfig(button++, this::requestLicense, // + LicenseStatusDialogMessages.LicenseStatusDialog_intention_request, // + LicenseStatusDialogMessages.LicenseStatusDialog_intention_request_tooltip, "")//$NON-NLS-1$ + .reside(buttons); + new ButtonConfig(button++, this::importLicense, // + LicenseStatusDialogMessages.LicenseStatusDialog_intention_import, // + LicenseStatusDialogMessages.LicenseStatusDialog_intention_import_tooltip, "") //$NON-NLS-1$ + .reside(buttons); + new ButtonConfig(button++, copy(), // + LicenseStatusDialogMessages.LicenseStatusDialog_intention_copy, + LicenseStatusDialogMessages.LicenseStatusDialog_intention_copy_tooltip, "") //$NON-NLS-1$ + .reside(buttons); + if (haveUnacceptedAgreements()) { + new ButtonConfig(button++, this::exposeAgreements, // + LicenseStatusDialogMessages.LicenseStatusDialog_intention_accept, + LicenseStatusDialogMessages.LicenseStatusDialog_intention_accept_tooltip, "") //$NON-NLS-1$ + .reside(buttons); + } + if (!new NoErrors().test(diagnostic)) { + new ButtonConfig(button++, this::diagnose, // + LicenseStatusDialogMessages.LicenseStatusDialog_intention_diagnose, + LicenseStatusDialogMessages.LicenseStatusDialog_intention_diagnose_tooltip, "") //$NON-NLS-1$ + .reside(buttons); + } + } + + @Override + protected final void updateButtonsEnablement() { + // do nothing + } + + @Override + protected final void initMessage() { + new CertificateSummary(certificate).accept(this); + } + + protected abstract GoodIntention requestLicenseIntention(); + + protected abstract GoodIntention importLicenseIntention(); + + protected abstract GoodIntention diagnoseIntention(); + + protected abstract GoodIntention exposeLicenseAgreementsIntention(Collection collection); + + private void requestLicense() { + intention = requestLicenseIntention(); + super.okPressed(); + } + + private void importLicense() { + intention = importLicenseIntention(); + super.okPressed(); + } + + private void diagnose() { + intention = diagnoseIntention(); + super.okPressed(); + } + + private void exposeAgreements() { + intention = exposeLicenseAgreementsIntention(toExpose(certificate.agreements())); + super.okPressed(); + } + + private Collection toExpose(Collection agreements) { + return agreements.stream()// + .filter(this::toExpose)// + .collect(Collectors.toList()); + } + + private boolean toExpose(AgreementToAccept agreement) { + return !agreement.acceptance().accepted() && !agreement.acceptance().error().isPresent(); + } + + private boolean haveUnacceptedAgreements() { + return certificate.agreements().stream()// + .filter(this::toExpose)// + .findAny()// + .isPresent(); + } + + private Runnable copy() { + return new CopyToClipboard(this::getShell, // + new ExaminationExplained(certificate), // + new DiagnosticExplained(diagnostic)); + } + +} diff --git a/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/FromLocalFileSystem.java b/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/FromLocalFileSystem.java new file mode 100644 index 000000000..817e1d87c --- /dev/null +++ b/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/FromLocalFileSystem.java @@ -0,0 +1,57 @@ +package org.eclipse.passage.lic.internal.jface.dialogs.licensing; + +import java.nio.file.Path; +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; + +import org.eclipse.passage.lic.internal.jface.i18n.ImportLicenseDialogMessages; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.DirectoryDialog; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; + +public final class FromLocalFileSystem implements LicenseFilesControl { + + private Text path; + + @Override + public void install(Composite parent, Consumer> onLicenses) { + Composite composite = row(parent, 3); + new Label(composite, SWT.NONE).setText(ImportLicenseDialogMessages.ImportLicenseDialog_path_label); + path = new Text(composite, SWT.BORDER | SWT.READ_ONLY); + path.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + Button browse = new Button(composite, SWT.PUSH); + browse.setText(ImportLicenseDialogMessages.ImportLicenseDialog_browse); + browse.addListener(SWT.Selection, e -> browseAndLoad(onLicenses)); + } + + private void browseAndLoad(Consumer> onLicenses) { + onLicenses.accept(browse()); + } + + private Composite row(Composite parent, int columns) { + Composite row = new Composite(parent, SWT.NONE); + row.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + row.setLayout(new GridLayout(columns, false)); + return row; + } + + private List browse() { + DirectoryDialog dialog = new DirectoryDialog(path.getShell(), SWT.OPEN | SWT.SHEET); + dialog.setText(ImportLicenseDialogMessages.ImportLicenseDialog_browse_dialog_title); + String folder = dialog.open(); + if (folder == null) { + return Collections.emptyList(); + } + path.setText(folder); + List licenses = new AllLicensesFromFolder(folder).get(); + path.setData(licenses); + return licenses; + } + +} diff --git a/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/GoodIntention.java b/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/GoodIntention.java index 0e0fc77ee..b9bb4585d 100644 --- a/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/GoodIntention.java +++ b/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/GoodIntention.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2020, 2021 ArSysOp + * Copyright (c) 2020, 2024 ArSysOp * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License 2.0 which is available at @@ -9,6 +9,7 @@ * * Contributors: * ArSysOp - initial API and implementation + * ArSysOp - further support *******************************************************************************/ package org.eclipse.passage.lic.internal.jface.dialogs.licensing; @@ -27,7 +28,7 @@ public abstract class GoodIntention { */ public abstract boolean paveTheWay(); - final static class Nope extends GoodIntention { + public final static class Nope extends GoodIntention { @Override public boolean paveTheWay() { @@ -36,11 +37,11 @@ public boolean paveTheWay() { } - final static class ImportLicense extends GoodIntention { + public final static class ImportLicense extends GoodIntention { private final Supplier shell; - ImportLicense(Supplier shell) { + public ImportLicense(Supplier shell) { this.shell = shell; } @@ -50,11 +51,11 @@ public boolean paveTheWay() { } } - final static class RequestLicense extends GoodIntention { + public final static class RequestLicense extends GoodIntention { private final Supplier shell; - RequestLicense(Supplier shell) { + public RequestLicense(Supplier shell) { this.shell = shell; } @@ -65,12 +66,12 @@ public boolean paveTheWay() { } } - final static class Diagnose extends GoodIntention { + public final static class Diagnose extends GoodIntention { private final Supplier shell; private final Diagnostic diagnostic; - Diagnose(Supplier shell, Diagnostic diagnostic) { + public Diagnose(Supplier shell, Diagnostic diagnostic) { this.shell = shell; this.diagnostic = diagnostic; } @@ -82,12 +83,12 @@ public boolean paveTheWay() { } } - final static class ExposeLicenseAgreements extends GoodIntention { + public final static class ExposeLicenseAgreements extends GoodIntention { private final Supplier shell; private final Collection agreements; - ExposeLicenseAgreements(Supplier shell, Collection agreements) { + public ExposeLicenseAgreements(Supplier shell, Collection agreements) { this.shell = shell; this.agreements = agreements; } diff --git a/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/ImportLicenseDialog.java b/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/ImportLicenseDialog.java index 7a291dd9e..d22e07cc3 100644 --- a/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/ImportLicenseDialog.java +++ b/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/ImportLicenseDialog.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2020, 2023 ArSysOp + * Copyright (c) 2020, 2024 ArSysOp * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License 2.0 which is available at @@ -15,9 +15,11 @@ import java.nio.file.Path; import java.time.format.DateTimeFormatter; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; @@ -34,26 +36,25 @@ import org.eclipse.passage.lic.internal.equinox.access.RegisteredLibraries; import org.eclipse.passage.lic.internal.jface.i18n.ImportLicenseDialogMessages; import org.eclipse.passage.lic.jface.resource.LicensingImages; -import org.eclipse.swt.SWT; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.DirectoryDialog; -import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; @SuppressWarnings("restriction") public final class ImportLicenseDialog extends NotificationDialog { private final DateTimeFormatter dates = DateTimeFormatter.ofPattern("dd-MM-yyyy"); //$NON-NLS-1$ - private Libraries libraries = null; + private Optional libraries = Optional.empty(); + private final List licenses = new ArrayList<>(); + private final LicenseFilesControl source; private ButtonConfig action; - private Text path; public ImportLicenseDialog(Shell shell) { + this(shell, new FromLocalFileSystem()); + } + + public ImportLicenseDialog(Shell shell, LicenseFilesControl source) { super(shell); + this.source = Objects.requireNonNull(source); } @Override @@ -76,21 +77,7 @@ protected void initMessage() { } private void buildSelector(Composite parent) { - Composite composite = row(parent, 3); - new Label(composite, SWT.NONE).setText(ImportLicenseDialogMessages.ImportLicenseDialog_path_label); - path = new Text(composite, SWT.BORDER | SWT.READ_ONLY); - path.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); - Button browse = new Button(composite, SWT.PUSH); - browse.setText(ImportLicenseDialogMessages.ImportLicenseDialog_browse); - browse.addListener(SWT.Selection, e -> browseAndLoad()); - setButtonLayoutData(browse); - } - - private Composite row(Composite parent, int columns) { - Composite row = new Composite(parent, SWT.NONE); - row.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); - row.setLayout(new GridLayout(columns, false)); - return row; + source.install(parent, this::loadAndUpdate); } private void buildViewer(Composite parent) { @@ -123,25 +110,14 @@ private String evaluation(Condition condition) { condition.evaluationInstructions().type().identifier()); } - private void browseAndLoad() { - loadLicense(browse()); + private void loadAndUpdate(List files) { + licenses.clear(); + licenses.addAll(files); + exposeLicensesContent(files); updateButtonsEnablement(); } - private List browse() { - DirectoryDialog dialog = new DirectoryDialog(getShell(), SWT.OPEN | SWT.SHEET); - dialog.setText(ImportLicenseDialogMessages.ImportLicenseDialog_browse_dialog_title); - String folder = dialog.open(); - if (folder == null) { - return Collections.emptyList(); - } - path.setText(folder); - List licenses = new AllLicensesFromFolder(folder).get(); - path.setData(licenses); - return licenses; - } - - private void loadLicense(List files) { + private void exposeLicensesContent(List files) { Optional product = product(); if (!product.isPresent()) { return; @@ -191,27 +167,22 @@ private Optional product() { return product.data(); } - @SuppressWarnings("unchecked") private void doLicenseImport() { Optional product = product(); if (!product.isPresent()) { return; } - Object licenses = path.getData(); - if (licenses == null) { - return; - } - new LicenseSet((List) licenses, product.get(), libraries, this::setErrorMessage).install(); + new LicenseSet(licenses, product.get(), libraries, this::setErrorMessage).install(); okPressed(); } - private Libraries libraries() { - if (libraries == null) { + private Optional libraries() { + if (libraries.isEmpty()) { Optional product = product(); - if (!product.isPresent()) { - return null; + if (product.isEmpty()) { + return Optional.empty(); } - libraries = new Libraries(new RegisteredLibraries(), product::get); + libraries = Optional.of(new Libraries(new RegisteredLibraries(), product::get)); } return libraries; } diff --git a/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/LicenseFilesControl.java b/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/LicenseFilesControl.java new file mode 100644 index 000000000..4f8172666 --- /dev/null +++ b/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/LicenseFilesControl.java @@ -0,0 +1,13 @@ +package org.eclipse.passage.lic.internal.jface.dialogs.licensing; + +import java.nio.file.Path; +import java.util.List; +import java.util.function.Consumer; + +import org.eclipse.swt.widgets.Composite; + +public interface LicenseFilesControl { + + void install(Composite parent, Consumer> onLicenses); + +} diff --git a/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/LicenseSet.java b/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/LicenseSet.java index 017074e43..ac7107e5c 100644 --- a/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/LicenseSet.java +++ b/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/LicenseSet.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022 ArSysOp + * Copyright (c) 2022, 2024 ArSysOp * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License 2.0 which is available at @@ -9,6 +9,7 @@ * * Contributors: * ArSysOp - initial API and implementation + * ArSysOp - further support *******************************************************************************/ package org.eclipse.passage.lic.internal.jface.dialogs.licensing; @@ -36,11 +37,11 @@ final class LicenseSet { private final LicensedProduct product; private final List licenses; - private final Libraries libraries; + private final Optional libraries; private final Consumer error; private final Optional service; - LicenseSet(List licenses, LicensedProduct product, Libraries libraries, Consumer error) { + LicenseSet(List licenses, LicensedProduct product, Optional libraries, Consumer error) { this.licenses = licenses; this.product = product; this.libraries = libraries; @@ -79,7 +80,10 @@ private void installProductLicense(Path license) throws IOException { } private void installLibraryLicense(Path license) throws Exception { - Optional> result = libraries.installLicense(license); + if (libraries.isEmpty()) { + return; + } + Optional> result = libraries.get().installLicense(license); if (!result.isPresent()) { return; // no libraries } @@ -100,4 +104,5 @@ private boolean productRelevantLicense(Path license) { .map(conditions -> !conditions.isEmpty())// .orElse(Boolean.FALSE); } + } diff --git a/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/LicenseStatusDialog.java b/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/LicenseStatusDialog.java index a83d29a9d..bcf0e98c9 100644 --- a/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/LicenseStatusDialog.java +++ b/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/internal/jface/dialogs/licensing/LicenseStatusDialog.java @@ -13,147 +13,36 @@ package org.eclipse.passage.lic.internal.jface.dialogs.licensing; import java.util.Collection; -import java.util.stream.Collectors; import org.eclipse.passage.lic.api.agreements.AgreementToAccept; import org.eclipse.passage.lic.api.diagnostic.Diagnostic; import org.eclipse.passage.lic.api.restrictions.ExaminationCertificate; -import org.eclipse.passage.lic.base.diagnostic.DiagnosticExplained; -import org.eclipse.passage.lic.base.diagnostic.RequirementsCoverage; -import org.eclipse.passage.lic.base.diagnostic.NoErrors; -import org.eclipse.passage.lic.base.diagnostic.RequirementStatus; -import org.eclipse.passage.lic.base.restrictions.ExaminationExplained; -import org.eclipse.passage.lic.equinox.ProductContacts; -import org.eclipse.passage.lic.internal.jface.i18n.LicenseStatusDialogMessages; -import org.eclipse.swt.SWT; -import org.eclipse.swt.custom.StyledText; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Shell; -public final class LicenseStatusDialog extends NotificationDialog { - - private final ExaminationCertificate certificate; - private final Diagnostic diagnostic; - private GoodIntention intention = new GoodIntention.Nope(); // truly mutable ^:( - private StyledText notice; +public final class LicenseStatusDialog extends BaseLicenseStatusDialog { public LicenseStatusDialog(Shell shell, ExaminationCertificate certificate, Diagnostic diagnostic) { - super(shell); - this.certificate = certificate; - this.diagnostic = diagnostic; - } - - public GoodIntention goodIntention() { - return intention; + super(shell, certificate, diagnostic); } @Override - protected void configureShell(Shell shell) { - super.configureShell(shell); - shell.setText(LicenseStatusDialogMessages.LicenseStatusDialog_title); - shell.setImage(getDefaultImage()); - shell.setSize(840, 600); + protected GoodIntention requestLicenseIntention() { + return new GoodIntention.RequestLicense(this::getShell); } @Override - protected void buildUI(Composite parent) { - viewer = new HereTable(parent, RequirementStatus.class) // - .withColumn(LicenseStatusDialogMessages.LicenseStatusDialog_column_id, // - 600, RequirementStatus::feature) - .withColumn(LicenseStatusDialogMessages.LicenseStatusDialog_column_status, // - 200, RequirementStatus::status) - .viewer(); - notice = new StyledText(parent, SWT.BORDER | SWT.READ_ONLY); - notice.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + protected GoodIntention importLicenseIntention() { + return new GoodIntention.ImportLicense(this::getShell); } @Override - protected void inplaceData() { - viewer.setInput(new RequirementsCoverage(certificate).get()); - notice.setText(new ProductContacts().get()); + protected GoodIntention diagnoseIntention() { + return new GoodIntention.Diagnose(this::getShell, diagnostic); } @Override - protected void initButtons() { - int button = 1; - new ButtonConfig(button++, this::requestLicense, // - LicenseStatusDialogMessages.LicenseStatusDialog_intention_request, // - LicenseStatusDialogMessages.LicenseStatusDialog_intention_request_tooltip, "")//$NON-NLS-1$ - .reside(buttons); - new ButtonConfig(button++, this::importLicense, // - LicenseStatusDialogMessages.LicenseStatusDialog_intention_import, // - LicenseStatusDialogMessages.LicenseStatusDialog_intention_import_tooltip, "") //$NON-NLS-1$ - .reside(buttons); - new ButtonConfig(button++, copy(), // - LicenseStatusDialogMessages.LicenseStatusDialog_intention_copy, - LicenseStatusDialogMessages.LicenseStatusDialog_intention_copy_tooltip, "") //$NON-NLS-1$ - .reside(buttons); - if (haveUnacceptedAgreements()) { - new ButtonConfig(button++, this::exposeAgreements, // - LicenseStatusDialogMessages.LicenseStatusDialog_intention_accept, - LicenseStatusDialogMessages.LicenseStatusDialog_intention_accept_tooltip, "") //$NON-NLS-1$ - .reside(buttons); - } - if (!new NoErrors().test(diagnostic)) { - new ButtonConfig(button++, this::diagnose, // - LicenseStatusDialogMessages.LicenseStatusDialog_intention_diagnose, - LicenseStatusDialogMessages.LicenseStatusDialog_intention_diagnose_tooltip, "") //$NON-NLS-1$ - .reside(buttons); - } - } - - @Override - protected void updateButtonsEnablement() { - // do nothing - } - - @Override - protected void initMessage() { - new CertificateSummary(certificate).accept(this); - } - - private void requestLicense() { - intention = new GoodIntention.RequestLicense(this::getShell); - super.okPressed(); - } - - private void importLicense() { - intention = new GoodIntention.ImportLicense(this::getShell); - super.okPressed(); - } - - private void diagnose() { - intention = new GoodIntention.Diagnose(this::getShell, diagnostic); - super.okPressed(); - } - - private void exposeAgreements() { - intention = new GoodIntention.ExposeLicenseAgreements(this::getShell, toExpose(certificate.agreements())); - super.okPressed(); - } - - private Collection toExpose(Collection agreements) { - return agreements.stream()// - .filter(this::toExpose)// - .collect(Collectors.toList()); - } - - private boolean toExpose(AgreementToAccept agreement) { - return !agreement.acceptance().accepted() && !agreement.acceptance().error().isPresent(); - } - - private boolean haveUnacceptedAgreements() { - return certificate.agreements().stream()// - .filter(this::toExpose)// - .findAny()// - .isPresent(); - } - - private Runnable copy() { - return new CopyToClipboard(this::getShell, // - new ExaminationExplained(certificate), // - new DiagnosticExplained(diagnostic)); + protected GoodIntention exposeLicenseAgreementsIntention(Collection agreements) { + return new GoodIntention.ExposeLicenseAgreements(this::getShell, agreements); } } diff --git a/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/jface/BaseEquinoxPassageUI.java b/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/jface/BaseEquinoxPassageUI.java new file mode 100644 index 000000000..646379cf9 --- /dev/null +++ b/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/jface/BaseEquinoxPassageUI.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * Copyright (c) 2020, 2024 ArSysOp + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * https://www.eclipse.org/legal/epl-2.0/. + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * ArSysOp - initial API and implementation + * ArSysOp - further support + *******************************************************************************/ +package org.eclipse.passage.lic.jface; + +import java.util.Optional; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.Supplier; + +import org.eclipse.jface.window.Window; +import org.eclipse.passage.lic.api.PassageUI; +import org.eclipse.passage.lic.api.ServiceInvocationResult; +import org.eclipse.passage.lic.api.access.GrantLockAttempt; +import org.eclipse.passage.lic.api.diagnostic.Diagnostic; +import org.eclipse.passage.lic.api.diagnostic.Trouble; +import org.eclipse.passage.lic.api.diagnostic.TroubleCode; +import org.eclipse.passage.lic.api.restrictions.ExaminationCertificate; +import org.eclipse.passage.lic.base.BaseServiceInvocationResult; +import org.eclipse.passage.lic.base.restrictions.CertificateIsSufficient; +import org.eclipse.passage.lic.equinox.EquinoxPassage; +import org.eclipse.passage.lic.equinox.EquinoxPassageLicenseCoverage; +import org.eclipse.passage.lic.internal.jface.dialogs.licensing.BaseLicenseStatusDialog; +import org.eclipse.passage.lic.internal.jface.dialogs.licensing.DiagnosticDialog; +import org.eclipse.swt.widgets.Shell; + +public abstract class BaseEquinoxPassageUI implements PassageUI { + + protected final Supplier shell; + + protected BaseEquinoxPassageUI(Supplier shell) { + this.shell = shell; + } + + @Override + public final ServiceInvocationResult acquireLicense(String feature) { + return investigate(// + () -> acquire(feature), // + GrantLockAttempt::certificate, // + new CertificateIsSufficient(feature)); + } + + @Override + public final ServiceInvocationResult assessLicensingStatus() { + return investigate(this::assess, Function.identity(), c -> false); + } + + private ServiceInvocationResult investigate(// + Supplier> service, // + Function certificate, // + Predicate> ok) { + ServiceInvocationResult result = service.get(); + try { + while (exposeAndMayBeEvenFix(result, certificate, ok)) { + result = service.get(); + } + } catch (Exception e) { + return new BaseServiceInvocationResult<>(new Trouble(// + new TroubleCode.Of(-1, "Unexpected error"), //$NON-NLS-1$ + "One of supplied subservices failed", //$NON-NLS-1$ + e)); + } + return result; + } + + private ServiceInvocationResult acquire(String feature) { + return new EquinoxPassage().acquireLicense(feature); + } + + private ServiceInvocationResult assess() { + return new EquinoxPassageLicenseCoverage().assess(); + } + + /** + * @return {@code true} if licensing state has been changed and new assessment + * have sense, {@code false} otherwise. + */ + private boolean exposeAndMayBeEvenFix(// + ServiceInvocationResult result, // + Function get, // + Predicate> ok) { + if (!result.data().isPresent()) { + new DiagnosticDialog(shell.get(), result.diagnostic()).open(); + return false; + } + Optional certificate = Optional.of(get.apply(result.data().get())); + if (ok.test(certificate)) { + return false; + } + BaseLicenseStatusDialog dialog = licenseStatusDialog(shell.get(), certificate.get(), result.diagnostic()); + if (Window.OK != dialog.open()) { + return false; + } + return dialog.goodIntention().paveTheWay(); + } + + protected abstract BaseLicenseStatusDialog licenseStatusDialog(Shell sh, ExaminationCertificate certificate, + Diagnostic diagnostic); + +} diff --git a/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/jface/EquinoxPassageUI.java b/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/jface/EquinoxPassageUI.java index 7b43ea701..512c41952 100644 --- a/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/jface/EquinoxPassageUI.java +++ b/bundles/org.eclipse.passage.lic.jface/src/org/eclipse/passage/lic/jface/EquinoxPassageUI.java @@ -13,94 +13,25 @@ *******************************************************************************/ package org.eclipse.passage.lic.jface; -import java.util.Optional; -import java.util.function.Function; -import java.util.function.Predicate; import java.util.function.Supplier; -import org.eclipse.jface.window.Window; import org.eclipse.passage.lic.api.PassageUI; -import org.eclipse.passage.lic.api.ServiceInvocationResult; -import org.eclipse.passage.lic.api.access.GrantLockAttempt; -import org.eclipse.passage.lic.api.diagnostic.Trouble; -import org.eclipse.passage.lic.api.diagnostic.TroubleCode; +import org.eclipse.passage.lic.api.diagnostic.Diagnostic; import org.eclipse.passage.lic.api.restrictions.ExaminationCertificate; -import org.eclipse.passage.lic.base.BaseServiceInvocationResult; -import org.eclipse.passage.lic.base.restrictions.CertificateIsSufficient; -import org.eclipse.passage.lic.equinox.EquinoxPassage; -import org.eclipse.passage.lic.equinox.EquinoxPassageLicenseCoverage; -import org.eclipse.passage.lic.internal.jface.dialogs.licensing.DiagnosticDialog; +import org.eclipse.passage.lic.internal.jface.dialogs.licensing.BaseLicenseStatusDialog; import org.eclipse.passage.lic.internal.jface.dialogs.licensing.LicenseStatusDialog; import org.eclipse.swt.widgets.Shell; -public final class EquinoxPassageUI implements PassageUI { - - private final Supplier shell; +public final class EquinoxPassageUI extends BaseEquinoxPassageUI implements PassageUI { public EquinoxPassageUI(Supplier shell) { - this.shell = shell; - } - - @Override - public ServiceInvocationResult acquireLicense(String feature) { - return investigate(// - () -> acquire(feature), // - GrantLockAttempt::certificate, // - new CertificateIsSufficient(feature)); + super(shell); } @Override - public ServiceInvocationResult assessLicensingStatus() { - return investigate(this::assess, Function.identity(), c -> false); - } - - private ServiceInvocationResult investigate(// - Supplier> service, // - Function certificate, // - Predicate> ok) { - ServiceInvocationResult result = service.get(); - try { - while (exposeAndMayBeEvenFix(result, certificate, ok)) { - result = service.get(); - } - } catch (Exception e) { - return new BaseServiceInvocationResult<>(new Trouble(// - new TroubleCode.Of(-1, "Unexpected error"), //$NON-NLS-1$ - "One of supplied subservices failed", //$NON-NLS-1$ - e)); - } - return result; - } - - private ServiceInvocationResult acquire(String feature) { - return new EquinoxPassage().acquireLicense(feature); - } - - private ServiceInvocationResult assess() { - return new EquinoxPassageLicenseCoverage().assess(); - } - - /** - * @return {@code true} if licensing state has been changed and new assessment - * have sense, {@code false} otherwise. - */ - private boolean exposeAndMayBeEvenFix(// - ServiceInvocationResult result, // - Function get, // - Predicate> ok) { - if (!result.data().isPresent()) { - new DiagnosticDialog(shell.get(), result.diagnostic()).open(); - return false; - } - Optional certificate = Optional.of(get.apply(result.data().get())); - if (ok.test(certificate)) { - return false; - } - LicenseStatusDialog dialog = new LicenseStatusDialog(shell.get(), certificate.get(), result.diagnostic()); - if (Window.OK != dialog.open()) { - return false; - } - return dialog.goodIntention().paveTheWay(); + protected BaseLicenseStatusDialog licenseStatusDialog(Shell sh, ExaminationCertificate certificate, + Diagnostic diagnostic) { + return new LicenseStatusDialog(shell.get(), certificate, diagnostic); } } diff --git a/bundles/org.eclipse.passage.loc.dashboard.ui/src/org/eclipse/passage/loc/dashboard/ui/wizards/LicenseIssuedNotification.java b/bundles/org.eclipse.passage.loc.dashboard.ui/src/org/eclipse/passage/loc/dashboard/ui/wizards/LicenseIssuedNotification.java index 6b1dd9333..266fb4da5 100644 --- a/bundles/org.eclipse.passage.loc.dashboard.ui/src/org/eclipse/passage/loc/dashboard/ui/wizards/LicenseIssuedNotification.java +++ b/bundles/org.eclipse.passage.loc.dashboard.ui/src/org/eclipse/passage/loc/dashboard/ui/wizards/LicenseIssuedNotification.java @@ -19,7 +19,6 @@ import org.eclipse.passage.loc.internal.api.IssuedFloatingLicense; import org.eclipse.passage.loc.internal.api.IssuedLicense; import org.eclipse.passage.loc.internal.dashboard.ui.i18n.IssueLicensePageMessages; -import org.eclipse.passage.loc.internal.licenses.ui.i18n.LicensesUiMessages; import org.eclipse.swt.program.Program; import org.eclipse.swt.widgets.Shell;