Skip to content
This repository was archived by the owner on Oct 4, 2021. It is now read-only.

Commit 0b8accb

Browse files
committed
[NuGet] Show license metadata in Manage Packages dialog
If the NuGet package source has license metadata then show this information instead of the View License link. License metadata can either be an license expression or a file. If the license is a file then clicking View License will open a separate dialog with the license read from the file. Fixes VSTS #1005394 - Support the new "license" properties in the NuGet package manager UI
1 parent 3016933 commit 0b8accb

File tree

12 files changed

+594
-6
lines changed

12 files changed

+594
-6
lines changed
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
//
2+
// LicenseFileDialog.cs
3+
//
4+
// Author:
5+
// Matt Ward <[email protected]>
6+
//
7+
// Copyright (c) 2019 Microsoft Corporation
8+
//
9+
// Permission is hereby granted, free of charge, to any person obtaining a copy
10+
// of this software and associated documentation files (the "Software"), to deal
11+
// in the Software without restriction, including without limitation the rights
12+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
// copies of the Software, and to permit persons to whom the Software is
14+
// furnished to do so, subject to the following conditions:
15+
//
16+
// The above copyright notice and this permission notice shall be included in
17+
// all copies or substantial portions of the Software.
18+
//
19+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
// THE SOFTWARE.
26+
27+
using System.ComponentModel;
28+
using NuGet.PackageManagement.UI;
29+
using Xwt;
30+
using Xwt.Formats;
31+
32+
namespace MonoDevelop.PackageManagement.Gui
33+
{
34+
class LicenseFileDialog : Dialog
35+
{
36+
RichTextView textView;
37+
LicenseFileText licenseFileText;
38+
39+
public LicenseFileDialog (LicenseFileText licenseFileText)
40+
{
41+
this.licenseFileText = licenseFileText;
42+
43+
Build ();
44+
LoadText ();
45+
46+
licenseFileText.PropertyChanged += LicenseFileTextPropertyChanged;
47+
licenseFileText.LoadLicenseFile ();
48+
}
49+
50+
void Build ()
51+
{
52+
Height = 450;
53+
Width = 450;
54+
Title = licenseFileText.LicenseHeader;
55+
56+
textView = new RichTextView ();
57+
Content = textView;
58+
59+
Buttons.Add (Command.Ok);
60+
DefaultCommand = Command.Ok;
61+
}
62+
63+
void LicenseFileTextPropertyChanged (object sender, PropertyChangedEventArgs e)
64+
{
65+
LoadText ();
66+
}
67+
68+
void LoadText ()
69+
{
70+
textView.LoadText (licenseFileText.LicenseText, TextFormat.Plain);
71+
}
72+
73+
protected override void Dispose (bool disposing)
74+
{
75+
base.Dispose (disposing);
76+
if (disposing) {
77+
licenseFileText.PropertyChanged -= LicenseFileTextPropertyChanged;
78+
}
79+
}
80+
}
81+
}

main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Gui/ManagePackagesDialog.UI.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,11 @@ internal partial class ManagePackagesDialog : ExtendedTitleBarDialog
4747
Label packageAuthor;
4848
Label packagePublishedDate;
4949
Label packageDownloads;
50+
Label packageLicenseLabel;
5051
LinkLabel packageLicenseLink;
52+
VBox packageLicenseMetadataWarningsVBox;
53+
HBox packageLicenseMetadataHBox;
54+
Label packageLicenseMetadataLabel;
5155
LinkLabel packageProjectPageLink;
5256
Label packageDependenciesList;
5357
HBox packageDependenciesHBox;
@@ -322,7 +326,7 @@ void Build ()
322326
var packageLicenseHBox = new HBox ();
323327
packageInfoVBox.PackStart (packageLicenseHBox);
324328

325-
var packageLicenseLabel = new Label ();
329+
packageLicenseLabel = new Label ();
326330
packageLicenseLabel.Text = GettextCatalog.GetString ("License");
327331
packageLicenseLabel.Font = packageInfoBoldFont;
328332
packageLicenseHBox.PackStart (packageLicenseLabel);
@@ -332,6 +336,21 @@ void Build ()
332336
packageLicenseLink.Font = packageInfoSmallFont;
333337
packageLicenseHBox.PackEnd (packageLicenseLink);
334338

339+
packageLicenseMetadataWarningsVBox = new VBox ();
340+
packageLicenseMetadataWarningsVBox.Visible = false;
341+
packageInfoVBox.PackStart (packageLicenseMetadataWarningsVBox);
342+
343+
packageLicenseMetadataHBox = new HBox ();
344+
packageLicenseMetadataHBox.Visible = false;
345+
packageInfoVBox.PackStart (packageLicenseMetadataHBox);
346+
347+
packageLicenseMetadataLabel = new Label ();
348+
packageLicenseMetadataLabel.Wrap = WrapMode.Word;
349+
packageLicenseMetadataLabel.MarginLeft = 5;
350+
packageLicenseMetadataLabel.Font = packageInfoSmallFont;
351+
packageLicenseMetadataLabel.Accessible.LabelWidget = packageLicenseLabel;
352+
packageLicenseMetadataHBox.PackStart (packageLicenseMetadataLabel, true);
353+
335354
// Package project page.
336355
var packageProjectPageHBox = new HBox ();
337356
packageInfoVBox.PackStart (packageProjectPageHBox);

main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Gui/ManagePackagesDialog.cs

Lines changed: 167 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,12 @@
2727
using System;
2828
using System.Collections.Generic;
2929
using System.Linq;
30+
using System.Security;
3031
using MonoDevelop.Core;
3132
using MonoDevelop.Ide;
33+
using MonoDevelop.PackageManagement.Gui;
3234
using MonoDevelop.Projects;
35+
using NuGet.PackageManagement.UI;
3336
using NuGet.Versioning;
3437
using Xwt;
3538
using Xwt.Drawing;
@@ -97,6 +100,8 @@ public ManagePackagesDialog (
97100
LoadViewModel (initialSearch);
98101

99102
closeButton.Clicked += CloseButtonClicked;
103+
packageLicenseLink.NavigateToUrl += PackageLicenseNavigateToUrl;
104+
packageLicenseMetadataLabel.LinkClicked += PackageLicenseLinkClicked;
100105
this.showPrereleaseCheckBox.Clicked += ShowPrereleaseCheckBoxClicked;
101106
this.packageSourceComboBox.SelectionChanged += PackageSourceChanged;
102107
this.addPackagesButton.Clicked += AddPackagesButtonClicked;
@@ -115,6 +120,8 @@ public ManagePackagesDialog (
115120
protected override void Dispose (bool disposing)
116121
{
117122
closeButton.Clicked -= CloseButtonClicked;
123+
packageLicenseLink.NavigateToUrl -= PackageLicenseNavigateToUrl;
124+
packageLicenseMetadataLabel.LinkClicked -= PackageLicenseLinkClicked;
118125
currentPackageVersionLabel.BoundsChanged -= PackageVersionLabelBoundsChanged;
119126

120127
imageLoader.Loaded -= ImageLoaded;
@@ -408,6 +415,10 @@ void ShowPackageInformation (ManagePackagesSearchResultViewModel packageViewMode
408415
{
409416
bool consolidate = viewModel.IsConsolidatePageSelected;
410417

418+
foreach (Widget child in packageInfoVBox.Children) {
419+
child.Visible = !consolidate;
420+
}
421+
411422
if (consolidate) {
412423
projectsListViewLabel.Text = GettextCatalog.GetString ("Select projects and a version for a consolidation.");
413424
} else {
@@ -422,7 +433,7 @@ void ShowPackageInformation (ManagePackagesSearchResultViewModel packageViewMode
422433
this.packageId.Visible = packageViewModel.HasNoGalleryUrl;
423434
ShowUri (this.packageIdLink, packageViewModel.GalleryUrl, packageViewModel.Id);
424435
ShowUri (this.packageProjectPageLink, packageViewModel.ProjectUrl);
425-
ShowUri (this.packageLicenseLink, packageViewModel.LicenseUrl);
436+
ShowLicense (packageViewModel);
426437

427438
PopulatePackageDependencies (packageViewModel);
428439
}
@@ -442,10 +453,6 @@ void ShowPackageInformation (ManagePackagesSearchResultViewModel packageViewMode
442453
packageVersionsHBox.Visible = true;
443454
}
444455

445-
foreach (Widget child in packageInfoVBox.Children) {
446-
child.Visible = !consolidate;
447-
}
448-
449456
if (consolidate) {
450457
PopulateProjectList ();
451458
} else {
@@ -971,6 +978,7 @@ void SelectedPackageViewModelChanged (object sender, PropertyChangedEventArgs e)
971978
} else {
972979
if (!viewModel.IsConsolidatePageSelected) {
973980
packagePublishedDate.Text = viewModel.SelectedPackage.GetLastPublishedDisplayText ();
981+
ShowLicense (viewModel.SelectedPackage);
974982
PopulatePackageDependencies (viewModel.SelectedPackage);
975983
}
976984
}
@@ -1161,5 +1169,159 @@ void ProjectCheckBoxCellViewToggled (object sender, WidgetEventArgs e)
11611169

11621170
UpdateAddPackagesButton ();
11631171
}
1172+
1173+
void ShowLicense (ManagePackagesSearchResultViewModel packageViewModel)
1174+
{
1175+
if (packageViewModel.HasLicenseMetadata) {
1176+
ShowLicenseMetadata (packageViewModel);
1177+
} else {
1178+
packageLicenseMetadataHBox.Visible = false;
1179+
packageLicenseMetadataWarningsVBox.Visible = false;
1180+
ShowUri (packageLicenseLink, packageViewModel.LicenseUrl, GettextCatalog.GetString ("View License"));
1181+
}
1182+
}
1183+
1184+
static string GetUriMarkup (Uri uri, string text)
1185+
{
1186+
return string.Format (
1187+
"<a href=\"{0}\">{1}</a>",
1188+
uri != null ? SecurityElement.Escape (uri.ToString ()) : string.Empty,
1189+
SecurityElement.Escape (text));
1190+
}
1191+
1192+
void PackageLicenseNavigateToUrl (object sender, NavigateToUrlEventArgs e)
1193+
{
1194+
if (ShowLicenseFile (e.Uri)) {
1195+
e.SetHandled ();
1196+
}
1197+
}
1198+
1199+
bool ShowLicenseFile (Uri uri)
1200+
{
1201+
if (!uri.IsFile)
1202+
return false;
1203+
1204+
if (uri.Fragment?.Length > 0) {
1205+
if (int.TryParse (uri.Fragment.Substring (1), out int fileNumber)) {
1206+
ShowLicenseFile (fileNumber);
1207+
return true;
1208+
}
1209+
}
1210+
return false;
1211+
}
1212+
1213+
void PackageLicenseLinkClicked (object sender, LinkEventArgs e)
1214+
{
1215+
if (ShowLicenseFile (e.Target)) {
1216+
e.SetHandled ();
1217+
}
1218+
}
1219+
1220+
void ShowLicenseMetadata (ManagePackagesSearchResultViewModel packageViewModel)
1221+
{
1222+
List<WarningText> warnings = null;
1223+
var textLinks = packageViewModel.GetLicenseLinks ();
1224+
1225+
if (textLinks.Count == 0) {
1226+
packageLicenseLink.Visible = false;
1227+
packageLicenseMetadataHBox.Visible = false;
1228+
packageLicenseMetadataWarningsVBox.Visible = false;
1229+
return;
1230+
}
1231+
1232+
// Single link - show this on the same line as the License label.
1233+
if (textLinks.Count == 1) {
1234+
packageLicenseLink.Visible = true;
1235+
packageLicenseMetadataHBox.Visible = false;
1236+
packageLicenseMetadataWarningsVBox.Visible = false;
1237+
1238+
IText textLink = textLinks [0];
1239+
if (textLink is LicenseText licenseText) {
1240+
packageLicenseLink.Text = licenseText.Text;
1241+
packageLicenseLink.Uri = licenseText.Link;
1242+
return;
1243+
} else if (textLink is LicenseFileText licenseFileText) {
1244+
packageLicenseLink.Text = GettextCatalog.GetString ("View License");
1245+
packageLicenseLink.Uri = CreateLicenseFileUri (licenseFileText, 1);
1246+
return;
1247+
} else {
1248+
// Warning or plain text - handled below.
1249+
}
1250+
}
1251+
1252+
// Multiple text links. We need to allow these to wrap so show these below the license label.
1253+
var markupBuilder = StringBuilderCache.Allocate ();
1254+
1255+
int fileLicenseCount = 0; // Should be one but handle multiple.
1256+
foreach (IText textLink in textLinks) {
1257+
if (textLink is LicenseText licenseText) {
1258+
markupBuilder.Append (GetUriMarkup (licenseText.Link, licenseText.Text));
1259+
} else if (textLink is LicenseFileText licenseFileText) {
1260+
fileLicenseCount++;
1261+
markupBuilder.Append (GetUriMarkup (CreateLicenseFileUri (licenseFileText, fileLicenseCount), licenseFileText.Text));
1262+
} else if (textLink is WarningText warning) {
1263+
warnings ??= new List<WarningText> ();
1264+
warnings.Add (warning);
1265+
} else {
1266+
markupBuilder.Append (textLink.Text);
1267+
}
1268+
}
1269+
1270+
packageLicenseLink.Visible = false;
1271+
packageLicenseMetadataHBox.Visible = true;
1272+
packageLicenseMetadataLabel.Markup = StringBuilderCache.ReturnAndFree (markupBuilder);
1273+
1274+
if (warnings != null) {
1275+
AddWarnings (warnings);
1276+
} else {
1277+
packageLicenseMetadataWarningsVBox.Visible = false;
1278+
}
1279+
}
1280+
1281+
Uri CreateLicenseFileUri (LicenseFileText licenseFileText, int licenseCount)
1282+
{
1283+
return new Uri ($"file:///{licenseFileText.Text}#{licenseCount}");
1284+
}
1285+
1286+
void AddWarnings (List<WarningText> warnings)
1287+
{
1288+
foreach (Widget child in packageLicenseMetadataWarningsVBox.Children.ToArray ()) {
1289+
packageLicenseMetadataWarningsVBox.Remove (child);
1290+
child.Dispose ();
1291+
}
1292+
1293+
foreach (WarningText warning in warnings) {
1294+
var hbox = new HBox ();
1295+
var image = new ImageView {
1296+
Image = ImageService.GetIcon ("md-warning", Gtk.IconSize.Menu),
1297+
MarginLeft = packageLicenseMetadataLabel.MarginLeft,
1298+
VerticalPlacement = WidgetPlacement.Start,
1299+
};
1300+
image.Accessible.RoleDescription = GettextCatalog.GetString ("Warning Icon");
1301+
hbox.PackStart (image);
1302+
1303+
var label = new Label {
1304+
Text = warning.Text,
1305+
Font = packageLicenseMetadataLabel.Font,
1306+
Wrap = WrapMode.Word
1307+
};
1308+
image.Accessible.LabelWidget = label;
1309+
label.Accessible.LabelWidget = packageLicenseLabel;
1310+
hbox.PackStart (label, true, true);
1311+
1312+
packageLicenseMetadataWarningsVBox.PackStart (hbox);
1313+
}
1314+
1315+
packageLicenseMetadataWarningsVBox.Visible = true;
1316+
}
1317+
1318+
void ShowLicenseFile (int fileNumber)
1319+
{
1320+
LicenseFileText licenseFileText = viewModel.SelectedPackage.GetLicenseFile (fileNumber);
1321+
if (licenseFileText != null) {
1322+
var dialog = new LicenseFileDialog (licenseFileText);
1323+
dialog.Run (this);
1324+
}
1325+
}
11641326
}
11651327
}

main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.csproj

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,13 @@
368368
<Compile Include="MonoDevelop.PackageManagement\PackageManagementCanReferenceProjectExtension.cs" />
369369
<Compile Include="MonoDevelop.PackageManagement\UpdateMultipleNuGetPackagesAction.cs" />
370370
<Compile Include="MonoDevelop.PackageManagement\ProjectReferenceMaintainerCollection.cs" />
371+
<Compile Include="NuGet.PackageManagement.UI\Models\FreeText.cs" />
372+
<Compile Include="NuGet.PackageManagement.UI\Models\IText.cs" />
373+
<Compile Include="NuGet.PackageManagement.UI\Models\LicenseFileText.cs" />
374+
<Compile Include="NuGet.PackageManagement.UI\Models\LicenseText.cs" />
375+
<Compile Include="NuGet.PackageManagement.UI\Models\WarningText.cs" />
376+
<Compile Include="NuGet.PackageManagement.UI\PackageLicenseUtilities.cs" />
377+
<Compile Include="MonoDevelop.PackageManagement.Gui\LicenseFileDialog.cs" />
371378
</ItemGroup>
372379
<ItemGroup>
373380
<EmbeddedResource Include="MonoDevelop.PackageManagement.addin.xml" />

0 commit comments

Comments
 (0)