From 7af358912fec04c25c178e21276391d3d10b6162 Mon Sep 17 00:00:00 2001 From: Paul Hebble Date: Wed, 27 Nov 2019 14:21:33 -0600 Subject: [PATCH] Custom mod labels, favorites, hiding --- GUI/CKAN-GUI.csproj | 12 + GUI/EditLabelsDialog.Designer.cs | 314 ++++++++++++++++++ GUI/EditLabelsDialog.cs | 281 ++++++++++++++++ GUI/EditLabelsDialog.resx | 139 ++++++++ GUI/GUIConfiguration.cs | 5 + GUI/Labels/ModuleLabel.cs | 63 ++++ GUI/Labels/ModuleLabelList.cs | 67 ++++ .../de-DE/EditLabelsDialog.de-DE.resx | 138 ++++++++ GUI/Localization/de-DE/Main.de-DE.resx | 2 + GUI/Main.Designer.cs | 40 ++- GUI/Main.cs | 19 +- GUI/Main.resx | 2 + GUI/MainChangeset.cs | 13 +- GUI/MainInstall.cs | 1 + GUI/MainLabels.cs | 155 +++++++++ GUI/MainModList.cs | 76 ++++- GUI/Properties/Resources.Designer.cs | 63 ++++ GUI/Properties/Resources.de-DE.resx | 21 ++ GUI/Properties/Resources.en-US.resx | 1 + GUI/Properties/Resources.resx | 21 ++ 20 files changed, 1418 insertions(+), 15 deletions(-) create mode 100644 GUI/EditLabelsDialog.Designer.cs create mode 100644 GUI/EditLabelsDialog.cs create mode 100644 GUI/EditLabelsDialog.resx create mode 100644 GUI/Labels/ModuleLabel.cs create mode 100644 GUI/Labels/ModuleLabelList.cs create mode 100644 GUI/Localization/de-DE/EditLabelsDialog.de-DE.resx create mode 100644 GUI/MainLabels.cs diff --git a/GUI/CKAN-GUI.csproj b/GUI/CKAN-GUI.csproj index cdce598e77..a15aa2431c 100644 --- a/GUI/CKAN-GUI.csproj +++ b/GUI/CKAN-GUI.csproj @@ -116,6 +116,12 @@ Component + + Form + + + EditLabelsDialog.cs + Form @@ -144,6 +150,8 @@ KSPCommandLineOptionsDialog.cs + + Form @@ -168,6 +176,7 @@ Form + UserControl @@ -287,6 +296,9 @@ ..\..\CompatibleKspVersionsDialog.cs + + EditLabelsDialog.cs + ErrorDialog.cs diff --git a/GUI/EditLabelsDialog.Designer.cs b/GUI/EditLabelsDialog.Designer.cs new file mode 100644 index 0000000000..672e323985 --- /dev/null +++ b/GUI/EditLabelsDialog.Designer.cs @@ -0,0 +1,314 @@ +namespace CKAN +{ + partial class EditLabelsDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new SingleAssemblyComponentResourceManager(typeof(EditLabelsDialog)); + this.ToolTip = new System.Windows.Forms.ToolTip(); + this.LabelSelectionTree = new System.Windows.Forms.TreeView(); + this.SelectOrCreateLabel = new System.Windows.Forms.Label(); + this.EditDetailsPanel = new System.Windows.Forms.Panel(); + this.NameLabel = new System.Windows.Forms.Label(); + this.NameTextBox = new System.Windows.Forms.TextBox(); + this.ColorLabel = new System.Windows.Forms.Label(); + this.ColorButton = new System.Windows.Forms.Button(); + this.InstanceNameLabel = new System.Windows.Forms.Label(); + this.InstanceNameComboBox = new System.Windows.Forms.ComboBox(); + this.HideFromOtherFiltersCheckBox = new System.Windows.Forms.CheckBox(); + this.NotifyOnChangesCheckBox = new System.Windows.Forms.CheckBox(); + this.RemoveOnChangesCheckBox = new System.Windows.Forms.CheckBox(); + this.AlertOnInstallCheckBox = new System.Windows.Forms.CheckBox(); + this.RemoveOnInstallCheckBox = new System.Windows.Forms.CheckBox(); + this.CreateButton = new System.Windows.Forms.Button(); + this.CloseButton = new System.Windows.Forms.Button(); + this.SaveButton = new System.Windows.Forms.Button(); + this.CancelButton = new System.Windows.Forms.Button(); + this.DeleteButton = new System.Windows.Forms.Button(); + this.EditDetailsPanel.SuspendLayout(); + this.SuspendLayout(); + // + // ToolTip + // + this.ToolTip.AutoPopDelay = 10000; + this.ToolTip.InitialDelay = 250; + this.ToolTip.ReshowDelay = 250; + this.ToolTip.ShowAlways = true; + // + // CreateButton + // + this.CreateButton.Anchor = ((System.Windows.Forms.AnchorStyles)(System.Windows.Forms.AnchorStyles.Bottom + | System.Windows.Forms.AnchorStyles.Left)); + this.CreateButton.Location = new System.Drawing.Point(10, 10); + this.CreateButton.Name = "CreateButton"; + this.CreateButton.Size = new System.Drawing.Size(75, 23); + this.CreateButton.TabIndex = 0; + this.CreateButton.UseVisualStyleBackColor = true; + this.CreateButton.Click += new System.EventHandler(this.CreateButton_Click); + resources.ApplyResources(this.CreateButton, "CreateButton"); + // + // LabelSelectionTree + // + this.LabelSelectionTree.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left)))); + this.LabelSelectionTree.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.LabelSelectionTree.FullRowSelect = true; + this.LabelSelectionTree.HideSelection = false; + this.LabelSelectionTree.Indent = 16; + this.LabelSelectionTree.ItemHeight = 24; + this.LabelSelectionTree.Location = new System.Drawing.Point(10, 43); + this.LabelSelectionTree.Name = "LabelSelectionTree"; + this.LabelSelectionTree.Size = new System.Drawing.Size(125, 320); + this.LabelSelectionTree.ShowPlusMinus = false; + this.LabelSelectionTree.ShowRootLines = false; + this.LabelSelectionTree.ShowLines = false; + this.LabelSelectionTree.TabIndex = 0; + this.LabelSelectionTree.BeforeSelect += new System.Windows.Forms.TreeViewCancelEventHandler(LabelSelectionTree_BeforeSelect); + this.LabelSelectionTree.BeforeCollapse += new System.Windows.Forms.TreeViewCancelEventHandler(LabelSelectionTree_BeforeCollapse); + // + // SelectOrCreateLabel + // + this.SelectOrCreateLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)); + this.SelectOrCreateLabel.Location = new System.Drawing.Point(160, 50); + this.SelectOrCreateLabel.Name = "SelectOrCreateLabel"; + this.SelectOrCreateLabel.Size = new System.Drawing.Size(300, 23); + resources.ApplyResources(this.SelectOrCreateLabel, "SelectOrCreateLabel"); + // + // EditDetailsPanel + // + this.EditDetailsPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.EditDetailsPanel.Controls.Add(this.NameLabel); + this.EditDetailsPanel.Controls.Add(this.NameTextBox); + this.EditDetailsPanel.Controls.Add(this.ColorLabel); + this.EditDetailsPanel.Controls.Add(this.ColorButton); + this.EditDetailsPanel.Controls.Add(this.InstanceNameLabel); + this.EditDetailsPanel.Controls.Add(this.InstanceNameComboBox); + this.EditDetailsPanel.Controls.Add(this.HideFromOtherFiltersCheckBox); + this.EditDetailsPanel.Controls.Add(this.NotifyOnChangesCheckBox); + this.EditDetailsPanel.Controls.Add(this.RemoveOnChangesCheckBox); + this.EditDetailsPanel.Controls.Add(this.AlertOnInstallCheckBox); + this.EditDetailsPanel.Controls.Add(this.RemoveOnInstallCheckBox); + this.EditDetailsPanel.Controls.Add(this.SaveButton); + this.EditDetailsPanel.Controls.Add(this.CancelButton); + this.EditDetailsPanel.Controls.Add(this.DeleteButton); + this.EditDetailsPanel.Location = new System.Drawing.Point(135, 43); + this.EditDetailsPanel.Name = "EditDetailsPanel"; + this.EditDetailsPanel.Size = new System.Drawing.Size(350, 320); + this.EditDetailsPanel.TabIndex = 1; + this.EditDetailsPanel.Visible = false; + // + // NameLabel + // + this.NameLabel.AutoSize = true; + this.NameLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)); + this.NameLabel.Location = new System.Drawing.Point(10, 13); + this.NameLabel.Name = "NameLabel"; + this.NameLabel.Size = new System.Drawing.Size(75, 23); + resources.ApplyResources(this.NameLabel, "NameLabel"); + // + // NameTextBox + // + this.NameTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)); + this.NameTextBox.Location = new System.Drawing.Point(90, 10); + this.NameTextBox.Name = "NameTextBox"; + this.NameTextBox.Size = new System.Drawing.Size(125, 23); + resources.ApplyResources(this.NameTextBox, "NameTextBox"); + // + // ColorLabel + // + this.ColorLabel.AutoSize = true; + this.ColorLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)); + this.ColorLabel.Location = new System.Drawing.Point(10, 43); + this.ColorLabel.Name = "ColorLabel"; + this.ColorLabel.Size = new System.Drawing.Size(75, 23); + resources.ApplyResources(this.ColorLabel, "ColorLabel"); + // + // ColorButton + // + this.ColorButton.Anchor = ((System.Windows.Forms.AnchorStyles)(System.Windows.Forms.AnchorStyles.Bottom + | System.Windows.Forms.AnchorStyles.Left)); + this.ColorButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.ColorButton.Location = new System.Drawing.Point(90, 40); + this.ColorButton.Name = "ColorButton"; + this.ColorButton.Size = new System.Drawing.Size(50, 20); + this.ColorButton.UseVisualStyleBackColor = false; + this.ColorButton.Click += new System.EventHandler(this.ColorButton_Click); + resources.ApplyResources(this.ColorButton, "ColorButton"); + // + // InstanceNameLabel + // + this.InstanceNameLabel.AutoSize = true; + this.InstanceNameLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)); + this.InstanceNameLabel.Location = new System.Drawing.Point(10, 73); + this.InstanceNameLabel.Name = "InstanceNameLabel"; + this.InstanceNameLabel.Size = new System.Drawing.Size(75, 23); + resources.ApplyResources(this.InstanceNameLabel, "InstanceNameLabel"); + // + // InstanceNameComboBox + // + this.InstanceNameComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)); + this.InstanceNameComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.InstanceNameComboBox.Location = new System.Drawing.Point(90, 70); + this.InstanceNameComboBox.Name = "InstanceNameComboBox"; + this.InstanceNameComboBox.Size = new System.Drawing.Size(125, 23); + resources.ApplyResources(this.InstanceNameComboBox, "InstanceNameComboBox"); + // + // HideFromOtherFiltersCheckBox + // + this.HideFromOtherFiltersCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)(System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)); + this.HideFromOtherFiltersCheckBox.Location = new System.Drawing.Point(90, 100); + this.HideFromOtherFiltersCheckBox.Name = "HideFromOtherFiltersCheckBox"; + this.HideFromOtherFiltersCheckBox.Size = new System.Drawing.Size(200, 23); + resources.ApplyResources(this.HideFromOtherFiltersCheckBox, "HideFromOtherFiltersCheckBox"); + // + // NotifyOnChangesCheckBox + // + this.NotifyOnChangesCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)(System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)); + this.NotifyOnChangesCheckBox.Location = new System.Drawing.Point(90, 130); + this.NotifyOnChangesCheckBox.Name = "NotifyOnChangesCheckBox"; + this.NotifyOnChangesCheckBox.Size = new System.Drawing.Size(200, 23); + resources.ApplyResources(this.NotifyOnChangesCheckBox, "NotifyOnChangesCheckBox"); + // + // RemoveOnChangesCheckBox + // + this.RemoveOnChangesCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)(System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)); + this.RemoveOnChangesCheckBox.Location = new System.Drawing.Point(90, 160); + this.RemoveOnChangesCheckBox.Name = "RemoveOnChangesCheckBox"; + this.RemoveOnChangesCheckBox.Size = new System.Drawing.Size(200, 23); + resources.ApplyResources(this.RemoveOnChangesCheckBox, "RemoveOnChangesCheckBox"); + // + // AlertOnInstallCheckBox + // + this.AlertOnInstallCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)(System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)); + this.AlertOnInstallCheckBox.Location = new System.Drawing.Point(90, 190); + this.AlertOnInstallCheckBox.Name = "AlertOnInstallCheckBox"; + this.AlertOnInstallCheckBox.Size = new System.Drawing.Size(200, 23); + resources.ApplyResources(this.AlertOnInstallCheckBox, "AlertOnInstallCheckBox"); + // + // RemoveOnInstallCheckBox + // + this.RemoveOnInstallCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)(System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)); + this.RemoveOnInstallCheckBox.Location = new System.Drawing.Point(90, 220); + this.RemoveOnInstallCheckBox.Name = "RemoveOnInstallCheckBox"; + this.RemoveOnInstallCheckBox.Size = new System.Drawing.Size(200, 23); + resources.ApplyResources(this.RemoveOnInstallCheckBox, "RemoveOnInstallCheckBox"); + // + // SaveButton + // + this.SaveButton.Anchor = ((System.Windows.Forms.AnchorStyles)(System.Windows.Forms.AnchorStyles.Bottom + | System.Windows.Forms.AnchorStyles.Left)); + this.SaveButton.Location = new System.Drawing.Point(10, 290); + this.SaveButton.Name = "SaveButton"; + this.SaveButton.Size = new System.Drawing.Size(75, 23); + this.SaveButton.TabIndex = 0; + this.SaveButton.UseVisualStyleBackColor = true; + this.SaveButton.Click += new System.EventHandler(this.SaveButton_Click); + resources.ApplyResources(this.SaveButton, "SaveButton"); + // + // CancelButton + // + this.CancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)(System.Windows.Forms.AnchorStyles.Bottom + | System.Windows.Forms.AnchorStyles.Left)); + this.CancelButton.Location = new System.Drawing.Point(90, 290); + this.CancelButton.Name = "CancelButton"; + this.CancelButton.Size = new System.Drawing.Size(75, 23); + this.CancelButton.TabIndex = 0; + this.CancelButton.UseVisualStyleBackColor = true; + this.CancelButton.Click += new System.EventHandler(this.CancelButton_Click); + resources.ApplyResources(this.CancelButton, "CancelButton"); + // + // DeleteButton + // + this.DeleteButton.Anchor = ((System.Windows.Forms.AnchorStyles)(System.Windows.Forms.AnchorStyles.Bottom + | System.Windows.Forms.AnchorStyles.Left)); + this.DeleteButton.Location = new System.Drawing.Point(170, 290); + this.DeleteButton.Name = "DeleteButton"; + this.DeleteButton.Size = new System.Drawing.Size(75, 23); + this.DeleteButton.TabIndex = 0; + this.DeleteButton.UseVisualStyleBackColor = true; + this.DeleteButton.Click += new System.EventHandler(this.DeleteButton_Click); + resources.ApplyResources(this.DeleteButton, "DeleteButton"); + // + // CloseButton + // + this.CloseButton.Anchor = ((System.Windows.Forms.AnchorStyles)(System.Windows.Forms.AnchorStyles.Bottom + | System.Windows.Forms.AnchorStyles.Left)); + this.CloseButton.Location = new System.Drawing.Point(10, 367); + this.CloseButton.Name = "CloseButton"; + this.CloseButton.Size = new System.Drawing.Size(75, 23); + this.CloseButton.TabIndex = 2; + this.CloseButton.UseVisualStyleBackColor = true; + this.CloseButton.Click += new System.EventHandler(this.CloseButton_Click); + resources.ApplyResources(this.CloseButton, "CloseButton"); + // + // EditLabelsDialog + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(500, 400); + this.Controls.Add(this.CreateButton); + this.Controls.Add(this.LabelSelectionTree); + this.Controls.Add(this.SelectOrCreateLabel); + this.Controls.Add(this.EditDetailsPanel); + this.Controls.Add(this.CloseButton); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.Icon = Properties.Resources.AppIcon; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "EditLabelsDialog"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + resources.ApplyResources(this, "$this"); + this.ResumeLayout(false); + } + + #endregion + + private System.Windows.Forms.ToolTip ToolTip; + private System.Windows.Forms.TreeView LabelSelectionTree; + private System.Windows.Forms.Label SelectOrCreateLabel; + private System.Windows.Forms.Panel EditDetailsPanel; + private System.Windows.Forms.Label NameLabel; + private System.Windows.Forms.TextBox NameTextBox; + private System.Windows.Forms.Label InstanceNameLabel; + private System.Windows.Forms.ComboBox InstanceNameComboBox; + private System.Windows.Forms.CheckBox HideFromOtherFiltersCheckBox; + private System.Windows.Forms.CheckBox NotifyOnChangesCheckBox; + private System.Windows.Forms.CheckBox RemoveOnChangesCheckBox; + private System.Windows.Forms.CheckBox AlertOnInstallCheckBox; + private System.Windows.Forms.CheckBox RemoveOnInstallCheckBox; + private System.Windows.Forms.Label ColorLabel; + private System.Windows.Forms.Button ColorButton; + private System.Windows.Forms.Button CreateButton; + private System.Windows.Forms.Button CloseButton; + private System.Windows.Forms.Button SaveButton; + private System.Windows.Forms.Button CancelButton; + private System.Windows.Forms.Button DeleteButton; + } +} diff --git a/GUI/EditLabelsDialog.cs b/GUI/EditLabelsDialog.cs new file mode 100644 index 0000000000..cfcf47a876 --- /dev/null +++ b/GUI/EditLabelsDialog.cs @@ -0,0 +1,281 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using System.Drawing; +using System.Windows.Forms; +using log4net; + +namespace CKAN +{ + public partial class EditLabelsDialog : Form + { + public EditLabelsDialog(IUser user, KSPManager manager, ModuleLabelList labels) + { + InitializeComponent(); + this.user = user; + this.labels = labels; + InstanceNameComboBox.DataSource = new string[] { "" } + .Concat(manager.Instances.Keys).ToArray(); + LoadTree(); + + this.ToolTip.SetToolTip(NameTextBox, Properties.Resources.EditLabelsToolTipName); + this.ToolTip.SetToolTip(ColorButton, Properties.Resources.EditLabelsToolTipColor); + this.ToolTip.SetToolTip(InstanceNameComboBox, Properties.Resources.EditLabelsToolTipInstance); + this.ToolTip.SetToolTip(HideFromOtherFiltersCheckBox, Properties.Resources.EditLabelsToolTipHide); + this.ToolTip.SetToolTip(NotifyOnChangesCheckBox, Properties.Resources.EditLabelsToolTipNotifyOnChanges); + this.ToolTip.SetToolTip(RemoveOnChangesCheckBox, Properties.Resources.EditLabelsToolTipRemoveOnChanges); + this.ToolTip.SetToolTip(AlertOnInstallCheckBox, Properties.Resources.EditLabelsToolTipAlertOnInstall); + this.ToolTip.SetToolTip(RemoveOnInstallCheckBox, Properties.Resources.EditLabelsToolTipRemoveOnInstall); + } + + private void LoadTree() + { + LabelSelectionTree.BeginUpdate(); + LabelSelectionTree.Nodes.Clear(); + var groups = this.labels.Labels + .GroupBy(l => l.InstanceName) + .OrderBy(g => g.Key); + foreach (var group in groups) + { + string groupName = string.IsNullOrEmpty(group.Key) + ? Properties.Resources.ModuleLabelListGlobal + : group.Key; + var gnd = LabelSelectionTree.Nodes.Add(groupName); + gnd.NodeFont = new Font(LabelSelectionTree.Font, FontStyle.Bold); + foreach (ModuleLabel mlbl in group.OrderBy(l => l.Name)) + { + var lblnd = gnd.Nodes.Add(mlbl.Name); + lblnd.Tag = mlbl; + } + } + LabelSelectionTree.ExpandAll(); + LabelSelectionTree.EndUpdate(); + } + + private void LabelSelectionTree_BeforeSelect(Object sender, TreeViewCancelEventArgs e) + { + if (e.Node == null) + { + e.Cancel = false; + } + else if (e.Node.Tag == null) + { + e.Cancel = true; + } + else if (!TryCloseEdit()) + { + e.Cancel = true; + } + else + { + StartEdit(e.Node.Tag as ModuleLabel); + e.Cancel = false; + } + } + + private void LabelSelectionTree_BeforeCollapse(object sender, TreeViewCancelEventArgs e) + { + e.Cancel = true; + } + + private void CreateButton_Click(object sender, EventArgs e) + { + LabelSelectionTree.SelectedNode = null; + StartEdit(new ModuleLabel()); + } + + private void ColorButton_Click(object sender, EventArgs e) + { + var dlg = new ColorDialog() + { + AnyColor = true, + AllowFullOpen = true, + ShowHelp = true, + SolidColorOnly = true, + Color = ColorButton.BackColor, + }; + if (dlg.ShowDialog(this) == DialogResult.OK) + { + ColorButton.BackColor = dlg.Color; + } + } + + private void SaveButton_Click(object sender, EventArgs e) + { + string errMsg; + if (TrySave(out errMsg)) + { + LabelSelectionTree.SelectedNode = null; + } + else + { + user.RaiseError(errMsg); + } + } + + private void CancelButton_Click(object sender, EventArgs e) + { + EditDetailsPanel.Visible = false; + currentlyEditing = null; + LabelSelectionTree.SelectedNode = null; + } + + private void DeleteButton_Click(object sender, EventArgs e) + { + if (currentlyEditing != null && Main.Instance.YesNoDialog( + string.Format( + Properties.Resources.EditLabelsDialogConfirmDelete, + currentlyEditing.Name + ), + Properties.Resources.EditLabelsDialogDelete, + Properties.Resources.EditLabelsDialogCancel + )) + { + labels.Labels = labels.Labels + .Except(new ModuleLabel[] { currentlyEditing }) + .ToArray(); + EditDetailsPanel.Visible = false; + currentlyEditing = null; + LoadTree(); + } + } + + private void CloseButton_Click(object sender, EventArgs e) + { + if (TryCloseEdit()) + { + Close(); + } + } + + private void StartEdit(ModuleLabel lbl) + { + currentlyEditing = lbl; + + NameTextBox.Text = lbl.Name; + ColorButton.BackColor = lbl.Color; + InstanceNameComboBox.SelectedItem = lbl.InstanceName; + HideFromOtherFiltersCheckBox.Checked = lbl.Hide; + NotifyOnChangesCheckBox.Checked = lbl.NotifyOnChange; + RemoveOnChangesCheckBox.Checked = lbl.RemoveOnChange; + AlertOnInstallCheckBox.Checked = lbl.AlertOnInstall; + RemoveOnInstallCheckBox.Checked = lbl.RemoveOnInstall; + + DeleteButton.Enabled = labels.Labels.Contains(lbl); + + EditDetailsPanel.Visible = true; + EditDetailsPanel.BringToFront(); + NameTextBox.Focus(); + } + + private bool TryCloseEdit() + { + if (HasChanges()) + { + if (Main.Instance.YesNoDialog( + Properties.Resources.EditLabelsDialogSavePrompt, + Properties.Resources.EditLabelsDialogSave, + Properties.Resources.EditLabelsDialogDiscard + )) + { + string errMsg; + if (!TrySave(out errMsg)) + { + user.RaiseError(errMsg); + return false; + } + } + } + return true; + } + + private bool TrySave(out string errMsg) + { + if (EditingValid(out errMsg)) + { + if (!labels.Labels.Contains(currentlyEditing)) + { + labels.Labels = labels.Labels + .Concat(new ModuleLabel[] { currentlyEditing }) + .ToArray(); + } + currentlyEditing.Name = NameTextBox.Text; + currentlyEditing.Color = ColorButton.BackColor; + currentlyEditing.InstanceName = + string.IsNullOrWhiteSpace(InstanceNameComboBox.SelectedItem?.ToString()) + ? null + : InstanceNameComboBox.SelectedItem.ToString(); + currentlyEditing.Hide = HideFromOtherFiltersCheckBox.Checked; + currentlyEditing.NotifyOnChange = NotifyOnChangesCheckBox.Checked; + currentlyEditing.RemoveOnChange = RemoveOnChangesCheckBox.Checked; + currentlyEditing.AlertOnInstall = AlertOnInstallCheckBox.Checked; + currentlyEditing.RemoveOnInstall = RemoveOnInstallCheckBox.Checked; + + EditDetailsPanel.Visible = false; + currentlyEditing = null; + LoadTree(); + return true; + } + return false; + } + + private bool EditingValid(out string errMsg) + { + if (currentlyEditing == null) + { + errMsg = Properties.Resources.EditLabelsDialogNoRecord; + return false; + } + if (string.IsNullOrWhiteSpace(NameTextBox.Text)) + { + errMsg = Properties.Resources.EditLabelsDialogNameRequired; + return false; + } + var newInst = string.IsNullOrWhiteSpace(InstanceNameComboBox.SelectedItem?.ToString()) + ? null + : InstanceNameComboBox.SelectedItem.ToString(); + var found = labels.Labels.FirstOrDefault(l => + l != currentlyEditing + && l.Name == NameTextBox.Text + && (l.InstanceName == newInst + || newInst == null + || l.InstanceName == null) + ); + if (found != null) + { + errMsg = string.Format( + Properties.Resources.EditLabelsDialogAlreadyExists, + NameTextBox.Text, + found.InstanceName ?? Properties.Resources.ModuleLabelListGlobal + ); + return false; + } + errMsg = ""; + return true; + } + + private bool HasChanges() + { + var newInst = string.IsNullOrWhiteSpace(InstanceNameComboBox.SelectedItem?.ToString()) + ? null + : InstanceNameComboBox.SelectedItem.ToString(); + return EditDetailsPanel.Visible && currentlyEditing != null + && ( currentlyEditing.Name != NameTextBox.Text + || currentlyEditing.Color != ColorButton.BackColor + || currentlyEditing.InstanceName != newInst + || currentlyEditing.Hide != HideFromOtherFiltersCheckBox.Checked + || currentlyEditing.NotifyOnChange != NotifyOnChangesCheckBox.Checked + || currentlyEditing.RemoveOnChange != RemoveOnChangesCheckBox.Checked + || currentlyEditing.AlertOnInstall != AlertOnInstallCheckBox.Checked + || currentlyEditing.RemoveOnInstall != RemoveOnInstallCheckBox.Checked + ); + } + + private ModuleLabel currentlyEditing; + + private readonly IUser user; + private readonly ModuleLabelList labels; + + private static readonly ILog log = LogManager.GetLogger(typeof(EditLabelsDialog)); + } +} diff --git a/GUI/EditLabelsDialog.resx b/GUI/EditLabelsDialog.resx new file mode 100644 index 0000000000..63d193f16f --- /dev/null +++ b/GUI/EditLabelsDialog.resx @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Create + Select a label to edit or create a new one + Name: + Background: + Select... + Instance +(blank for all): + Hide from other filters + Notify on updates + Remove on updates + Alert on install + Remove on install + Close + Save + Cancel + Delete + Export... + Edit Labels + diff --git a/GUI/GUIConfiguration.cs b/GUI/GUIConfiguration.cs index 3e759807ef..4e8e527441 100644 --- a/GUI/GUIConfiguration.cs +++ b/GUI/GUIConfiguration.cs @@ -30,6 +30,11 @@ public class GUIConfiguration public int ActiveFilter = 0; + /// + /// Name of the label filter the user chose, if any + /// + public string CustomLabelFilter = null; + // Sort by the mod name (index = 2) column by default public int SortByColumnIndex = 2; public bool SortDescending = false; diff --git a/GUI/Labels/ModuleLabel.cs b/GUI/Labels/ModuleLabel.cs new file mode 100644 index 0000000000..77b7cbb535 --- /dev/null +++ b/GUI/Labels/ModuleLabel.cs @@ -0,0 +1,63 @@ +using System; +using System.Linq; +using System.Drawing; +using System.ComponentModel; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace CKAN +{ + [JsonObject(MemberSerialization.OptIn)] + public class ModuleLabel + { + [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] + public string Name; + + [JsonProperty("color", NullValueHandling = NullValueHandling.Ignore)] + public Color Color; + + [JsonProperty("instance_name", NullValueHandling = NullValueHandling.Ignore)] + public string InstanceName; + + [JsonProperty("hide", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] + [DefaultValue(false)] + public bool Hide; + + [JsonProperty("notify_on_change", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] + [DefaultValue(false)] + public bool NotifyOnChange; + + [JsonProperty("remove_on_change", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] + [DefaultValue(false)] + public bool RemoveOnChange; + + [JsonProperty("alert_on_install", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] + [DefaultValue(false)] + public bool AlertOnInstall; + + [JsonProperty("remove_on_install", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] + [DefaultValue(false)] + public bool RemoveOnInstall; + + [JsonProperty("module_identifiers", NullValueHandling = NullValueHandling.Ignore)] + public HashSet ModuleIdentifiers = new HashSet(); + + /// + /// Add a module to this label's group + /// + /// The identifier of the module to add + public void Add(string identifier) + { + ModuleIdentifiers.Add(identifier); + } + + /// + /// Remove a module from this label's group + /// + /// The identifier of the module to remove + public void Remove(string identifier) + { + ModuleIdentifiers.Remove(identifier); + } + } +} diff --git a/GUI/Labels/ModuleLabelList.cs b/GUI/Labels/ModuleLabelList.cs new file mode 100644 index 0000000000..91edbc0f6b --- /dev/null +++ b/GUI/Labels/ModuleLabelList.cs @@ -0,0 +1,67 @@ +using System; +using System.IO; +using System.Drawing; +using Newtonsoft.Json; + +namespace CKAN +{ + [JsonObject(MemberSerialization.OptIn)] + public class ModuleLabelList + { + [JsonProperty("labels", NullValueHandling = NullValueHandling.Ignore)] + public ModuleLabel[] Labels = new ModuleLabel[] {}; + + public static readonly string DefaultPath = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + "CKAN", + "labels.json" + ); + + public static ModuleLabelList GetDefaultLabels() + { + return new ModuleLabelList() { + Labels = new ModuleLabel[] { + new ModuleLabel() { + Name = Properties.Resources.ModuleLabelListFavourites, + Color = Color.PaleGreen, + }, + new ModuleLabel() { + Name = Properties.Resources.ModuleLabelListHidden, + Hide = true, + Color = Color.PaleVioletRed, + }, + } + }; + } + + public string[] LabelsMatchingModule(string identifier) + { + return new string[] {}; + } + + public static ModuleLabelList Load(string path) + { + try + { + return JsonConvert.DeserializeObject(File.ReadAllText(path)); + } + catch (FileNotFoundException ex) + { + return null; + } + } + + public bool Save(string path) + { + try + { + File.WriteAllText(path, JsonConvert.SerializeObject(this, Formatting.Indented)); + return true; + } + catch + { + return false; + } + } + } +} diff --git a/GUI/Localization/de-DE/EditLabelsDialog.de-DE.resx b/GUI/Localization/de-DE/EditLabelsDialog.de-DE.resx new file mode 100644 index 0000000000..bf93ffdf9d --- /dev/null +++ b/GUI/Localization/de-DE/EditLabelsDialog.de-DE.resx @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Erstellen + Wählen Sie eine Bezeichnung zum Bearbeiten oder erstellen Sie eine neue + Name: + Hintergrund: + Wählen... + Beispiel +(leer für alle): + Vor anderen Filtern verstecken + Bei Updates benachrichtigen + Bei Updates entfernen + Bei Installation benachrichtigen + Bei der Installation entfernen + Schließen + Speichern + Stornieren + Delete + Labels bearbeiten + diff --git a/GUI/Localization/de-DE/Main.de-DE.resx b/GUI/Localization/de-DE/Main.de-DE.resx index 994ea1d2f0..2c05cd335c 100644 --- a/GUI/Localization/de-DE/Main.de-DE.resx +++ b/GUI/Localization/de-DE/Main.de-DE.resx @@ -251,4 +251,6 @@ KSP-Verzeichnis öffnen CKAN Einstellungen Beenden + Etiketten + Labels bearbeiten ... diff --git a/GUI/Main.Designer.cs b/GUI/Main.Designer.cs index a7193913eb..a5a52e471b 100644 --- a/GUI/Main.Designer.cs +++ b/GUI/Main.Designer.cs @@ -87,7 +87,13 @@ private void InitializeComponent() this.DownloadCount = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.Description = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.ModListContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components); + this.LabelsContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components); this.ModListHeaderContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components); + this.modListToolStripSeparator = new System.Windows.Forms.ToolStripSeparator(); + this.customFilterToolStripSeparator = new System.Windows.Forms.ToolStripSeparator(); + this.labelsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.labelToolStripSeparator = new System.Windows.Forms.ToolStripSeparator(); + this.editLabelsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.reinstallToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.downloadContentsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.purgeContentsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -423,7 +429,9 @@ private void InitializeComponent() this.FilterNewButton, this.FilterNotInstalledButton, this.FilterIncompatibleButton, - this.FilterAllButton}); + this.FilterAllButton, + this.customFilterToolStripSeparator}); + this.FilterToolButton.DropDown.Opening += new System.ComponentModel.CancelEventHandler(FilterToolButton_DrodDown_Opening); this.FilterToolButton.Image = global::CKAN.Properties.Resources.filter; this.FilterToolButton.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; this.FilterToolButton.Name = "FilterToolButton"; @@ -698,12 +706,21 @@ private void InitializeComponent() // ModListContextMenuStrip // this.ModListContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.labelsToolStripMenuItem, + this.modListToolStripSeparator, this.reinstallToolStripMenuItem, this.downloadContentsToolStripMenuItem, this.purgeContentsToolStripMenuItem}); this.ModListContextMenuStrip.Name = "ModListContextMenuStrip"; this.ModListContextMenuStrip.Size = new System.Drawing.Size(180, 70); // + // labelsToolStripMenuItem + // + this.labelsToolStripMenuItem.Name = "labelsToolStripMenuItem"; + this.labelsToolStripMenuItem.Size = new System.Drawing.Size(179, 22); + this.labelsToolStripMenuItem.DropDown = this.LabelsContextMenuStrip; + resources.ApplyResources(this.labelsToolStripMenuItem, "labelsToolStripMenuItem"); + // // reinstallToolStripMenuItem // this.reinstallToolStripMenuItem.Name = "reinstallToolStripMenuItem"; @@ -725,6 +742,21 @@ private void InitializeComponent() this.purgeContentsToolStripMenuItem.Click += new System.EventHandler(this.purgeContentsToolStripMenuItem_Click); resources.ApplyResources(this.purgeContentsToolStripMenuItem, "purgeContentsToolStripMenuItem"); // + // LabelsContextMenuStrip + // + this.LabelsContextMenuStrip.Name = "LabelsContextMenuStrip"; + this.LabelsContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.editLabelsToolStripMenuItem}); + this.LabelsContextMenuStrip.Size = new System.Drawing.Size(180, 70); + this.LabelsContextMenuStrip.Opening += new System.ComponentModel.CancelEventHandler(LabelsContextMenuStrip_Opening); + // + // editLabelsToolStripMenuItem + // + this.editLabelsToolStripMenuItem.Name = "editLabelsToolStripMenuItem"; + this.editLabelsToolStripMenuItem.Size = new System.Drawing.Size(179, 22); + this.editLabelsToolStripMenuItem.Click += new System.EventHandler(this.editLabelsToolStripMenuItem_Click); + resources.ApplyResources(this.editLabelsToolStripMenuItem, "editLabelsToolStripMenuItem"); + // // ModListHeaderContextMenuStrip // this.ModListHeaderContextMenuStrip.Name = "ModListHeaderContextMenuStrip"; @@ -1444,7 +1476,13 @@ private void InitializeComponent() private System.Windows.Forms.DataGridViewTextBoxColumn DownloadCount; private System.Windows.Forms.DataGridViewTextBoxColumn Description; private System.Windows.Forms.ContextMenuStrip ModListContextMenuStrip; + private System.Windows.Forms.ToolStripSeparator modListToolStripSeparator; + private System.Windows.Forms.ToolStripSeparator customFilterToolStripSeparator; + private System.Windows.Forms.ContextMenuStrip LabelsContextMenuStrip; private System.Windows.Forms.ContextMenuStrip ModListHeaderContextMenuStrip; + private System.Windows.Forms.ToolStripMenuItem labelsToolStripMenuItem; + private System.Windows.Forms.ToolStripSeparator labelToolStripSeparator; + private System.Windows.Forms.ToolStripMenuItem editLabelsToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem reinstallToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem downloadContentsToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem purgeContentsToolStripMenuItem; diff --git a/GUI/Main.cs b/GUI/Main.cs index cc8fcb2e1b..40a5e4d055 100644 --- a/GUI/Main.cs +++ b/GUI/Main.cs @@ -206,6 +206,7 @@ public Main(string[] cmdlineArgs, KSPManager mgr, GUIUser user, bool showConsole minimizedContextMenuStrip.Renderer = new FlatToolStripRenderer(); ModListContextMenuStrip.Renderer = new FlatToolStripRenderer(); ModListHeaderContextMenuStrip.Renderer = new FlatToolStripRenderer(); + LabelsContextMenuStrip.Renderer = new FlatToolStripRenderer(); } // Initialize all user interaction dialogs. @@ -536,6 +537,7 @@ protected override void OnFormClosing(FormClosingEventArgs e) // Save the active filter configuration.ActiveFilter = (int)mainModList.ModFilter; + configuration.CustomLabelFilter = mainModList.CustomLabelFilter?.Name; // Save settings. configuration.Save(); @@ -587,7 +589,11 @@ private void CurrentInstanceUpdated(bool allowRepoUpdate) // Remove it again after it ran, else it stays there and is added again and again. void filterUpdate (object sender, RunWorkerCompletedEventArgs e) { - Filter((GUIModFilter)configuration.ActiveFilter); + Filter( + (GUIModFilter)configuration.ActiveFilter, + mainModList.ModuleLabels.Labels + .FirstOrDefault(l => l.Name == configuration.CustomLabelFilter) + ); m_UpdateRepoWorker.RunWorkerCompleted -= filterUpdate; } @@ -596,7 +602,11 @@ void filterUpdate (object sender, RunWorkerCompletedEventArgs e) else { UpdateModsList(); - Filter((GUIModFilter)configuration.ActiveFilter); + Filter( + (GUIModFilter)configuration.ActiveFilter, + mainModList.ModuleLabels.Labels + .FirstOrDefault(l => l.Name == configuration.CustomLabelFilter) + ); } ChangeSet = null; @@ -852,13 +862,15 @@ private void FilterAllButton_Click(object sender, EventArgs e) /// Called when the modlist filter (all, compatible, incompatible...) is changed. /// /// Filter. - private void Filter(GUIModFilter filter) + private void Filter(GUIModFilter filter, ModuleLabel label = null) { // Triggers mainModList.ModFiltersUpdated() mainModList.ModFilter = filter; + mainModList.CustomLabelFilter = label; // Save new filter to the configuration. configuration.ActiveFilter = (int)mainModList.ModFilter; + configuration.CustomLabelFilter = label?.Name; configuration.Save(); // Ask the configuration which columns to show. @@ -888,6 +900,7 @@ private void Filter(GUIModFilter filter) ModList.Columns["InstallDate"].Visible = false; ModList.Columns["AutoInstalled"].Visible = false; FilterToolButton.Text = Properties.Resources.MainFilterNotInstalled; break; + case GUIModFilter.CustomLabel: FilterToolButton.Text = label?.Name ?? "CUSTOM"; break; default: FilterToolButton.Text = Properties.Resources.MainFilterCompatible; break; } } diff --git a/GUI/Main.resx b/GUI/Main.resx index 09f3f50b19..81220c0ba6 100644 --- a/GUI/Main.resx +++ b/GUI/Main.resx @@ -260,4 +260,6 @@ Open KSP Directory CKAN Settings Quit + Labels + Edit labels... diff --git a/GUI/MainChangeset.cs b/GUI/MainChangeset.cs index 8900b25b5e..aa4c134573 100644 --- a/GUI/MainChangeset.cs +++ b/GUI/MainChangeset.cs @@ -1,7 +1,8 @@ -using System; +using System; +using System.Linq; using System.Collections.Generic; +using System.Drawing; using System.ComponentModel; -using System.Linq; using System.Windows.Forms; namespace CKAN @@ -47,14 +48,18 @@ public void UpdateChangesDialog(List changeset, BackgroundWorker inst } CkanModule m = change.Mod; + bool warn = AnyLabelAlertsBeforeInstall(m); ChangesListView.Items.Add(new ListViewItem(new string[] { change.NameAndStatus, change.ChangeType.ToString(), - change.Description + warn + ? string.Format(Properties.Resources.MainChangesetWarningInstallingHidden, change.Description) + : change.Description }) { - Tag = m + Tag = m, + ForeColor = warn ? Color.Red : SystemColors.WindowText }); } } diff --git a/GUI/MainInstall.cs b/GUI/MainInstall.cs index c5ae24b931..e664d8d56a 100644 --- a/GUI/MainInstall.cs +++ b/GUI/MainInstall.cs @@ -317,6 +317,7 @@ private void InstallMods(object sender, DoWorkEventArgs e) private void OnModInstalled(CkanModule mod) { AddStatusMessage(string.Format(Properties.Resources.MainInstallModSuccess, mod.name)); + LabelsAfterInstall(mod); } private void PostInstallMods(object sender, RunWorkerCompletedEventArgs e) diff --git a/GUI/MainLabels.cs b/GUI/MainLabels.cs new file mode 100644 index 0000000000..ee6cbdf35f --- /dev/null +++ b/GUI/MainLabels.cs @@ -0,0 +1,155 @@ +using System; +using System.Linq; +using System.ComponentModel; +using System.Windows.Forms; +using System.Collections.Generic; + +namespace CKAN +{ + public partial class Main + { + #region Filter dropdown + + private void FilterToolButton_DrodDown_Opening(object sender, System.ComponentModel.CancelEventArgs e) + { + // Remove any existing custom labels from the list + for (int i = FilterToolButton.DropDownItems.Count - 1; i >= 0; --i) + { + if (FilterToolButton.DropDownItems[i] is ToolStripSeparator) + { + // Stop when we get to the separator + break; + } + FilterToolButton.DropDownItems.RemoveAt(i); + } + foreach (ModuleLabel mlbl in mainModList.ModuleLabels.Labels) + { + FilterToolButton.DropDownItems.Add(new ToolStripMenuItem( + $"{mlbl.Name} ({mlbl.ModuleIdentifiers.Count})", + null, customFilterButton_Click + ) + { + Tag = mlbl + }); + } + } + + private void customFilterButton_Click(object sender, EventArgs e) + { + var clicked = sender as ToolStripMenuItem; + Filter(GUIModFilter.CustomLabel, clicked.Tag as ModuleLabel); + } + + #endregion + + #region Right click menu + + private void LabelsContextMenuStrip_Opening(object sender, System.ComponentModel.CancelEventArgs e) + { + LabelsContextMenuStrip.Items.Clear(); + + var module = GetSelectedModule(); + foreach (ModuleLabel mlbl in mainModList.ModuleLabels.Labels) + { + if (mlbl.InstanceName == null || mlbl.InstanceName == CurrentInstance.Name) + { + LabelsContextMenuStrip.Items.Add( + new ToolStripMenuItem(mlbl.Name, null, labelMenuItem_Click) + { + Checked = mlbl.ModuleIdentifiers.Contains(module.Identifier), + CheckOnClick = true, + Tag = mlbl, + } + ); + } + } + LabelsContextMenuStrip.Items.Add(labelToolStripSeparator); + LabelsContextMenuStrip.Items.Add(editLabelsToolStripMenuItem); + e.Cancel = false; + } + + private void labelMenuItem_Click(object sender, EventArgs e) + { + var item = sender as ToolStripMenuItem; + var mlbl = item.Tag as ModuleLabel; + var module = GetSelectedModule(); + if (item.Checked) + { + mlbl.Add(module.Identifier); + } + else + { + mlbl.Remove(module.Identifier); + } + mainModList.ModuleLabels.Save(ModuleLabelList.DefaultPath); + mainModList.ReapplyLabels(module); + } + + private void editLabelsToolStripMenuItem_Click(object sender, EventArgs e) + { + EditLabelsDialog eld = new EditLabelsDialog(currentUser, Manager, mainModList.ModuleLabels); + eld.ShowDialog(this); + eld.Dispose(); + mainModList.ModuleLabels.Save(ModuleLabelList.DefaultPath); + } + + #endregion + + #region Notifications + + private void LabelsAfterUpdate(IEnumerable mods) + { + Util.Invoke(Main.Instance, () => + { + var notifLabs = mainModList.ModuleLabels.Labels.Where(l => l.NotifyOnChange); + var toNotif = mods + .Where(m => + notifLabs.Any(l => + l.ModuleIdentifiers.Contains(m.Identifier))) + .Select(m => m.Name) + .ToArray(); + if (toNotif.Any()) + { + MessageBox.Show( + string.Format( + "Some of your watched mods have updated:\r\n\r\n{0}", + string.Join("\r\n", toNotif) + ), + "Update Notifications", + MessageBoxButtons.OK + ); + } + + foreach (GUIMod mod in mods) + { + foreach (ModuleLabel l in mainModList.ModuleLabels.Labels + .Where(l => l.RemoveOnChange + && l.ModuleIdentifiers.Contains(mod.Identifier))) + { + l.Remove(mod.Identifier); + } + + } + }); + } + + private bool AnyLabelAlertsBeforeInstall(CkanModule mod) + { + return mainModList.ModuleLabels.Labels + .Where(l => l.AlertOnInstall) + .Any(l => l.ModuleIdentifiers.Contains(mod.identifier)); + } + + private void LabelsAfterInstall(CkanModule mod) + { + foreach (ModuleLabel l in mainModList.ModuleLabels.Labels + .Where(l => l.RemoveOnInstall + && l.ModuleIdentifiers.Contains(mod.identifier))) + { + l.Remove(mod.identifier); + } + } + + #endregion + } +} diff --git a/GUI/MainModList.cs b/GUI/MainModList.cs index 62c5723bfb..77693ecdca 100644 --- a/GUI/MainModList.cs +++ b/GUI/MainModList.cs @@ -25,6 +25,7 @@ public enum GUIModFilter Cached = 7, Replaceable = 8, Uncached = 9, + CustomLabel = 10, } public partial class Main @@ -201,6 +202,7 @@ private void _UpdateModsList(IEnumerable mc, Dictionary ); AddLogMessage(Properties.Resources.MainModListPreservingNew); + var toNotify = new HashSet(); if (old_modules != null) { foreach (GUIMod gm in gui_mods) @@ -211,6 +213,7 @@ private void _UpdateModsList(IEnumerable mc, Dictionary if (!gm.IsIncompatible && oldIncompat) { gm.IsNew = true; + toNotify.Add(gm); } } else @@ -230,13 +233,14 @@ private void _UpdateModsList(IEnumerable mc, Dictionary gui_mod.IsNew = true; } } + LabelsAfterUpdate(toNotify); AddLogMessage(Properties.Resources.MainModListPopulatingList); // Update our mod listing mainModList.ConstructModList(gui_mods.ToList(), mc, configuration.HideEpochs, configuration.HideV); mainModList.Modules = new ReadOnlyCollection( mainModList.full_list_of_mod_rows.Values.Select(row => row.Tag as GUIMod).ToList()); - + UpdateChangeSetAndConflicts(registry); AddLogMessage(Properties.Resources.MainModListUpdatingFilters); @@ -576,7 +580,7 @@ await UpdateChangeSetAndConflicts( } } } - + private void ModList_GotFocus(object sender, EventArgs e) { Util.Invoke(this, () => @@ -695,6 +699,24 @@ public GUIModFilter ModFilter } } + public readonly ModuleLabelList ModuleLabels = ModuleLabelList.Load(ModuleLabelList.DefaultPath) + ?? ModuleLabelList.GetDefaultLabels(); + + private ModuleLabel _customLabelFilter; + public ModuleLabel CustomLabelFilter + { + get { return _customLabelFilter; } + set + { + var old = _customLabelFilter; + _customLabelFilter = value; + if (!old?.Equals(value) ?? !value?.Equals(old) ?? false) + { + ModFiltersUpdated(this); + } + } + } + public string ModNameFilter { get { return _modNameFilter; } @@ -825,19 +847,19 @@ public bool IsVisible(GUIMod mod) var nameMatchesFilter = IsNameInNameFilter(mod); var authorMatchesFilter = IsAuthorInAuthorFilter(mod); var abstractMatchesFilter = IsAbstractInDescriptionFilter(mod); - var modMatchesType = IsModInFilter(ModFilter, mod); + var modMatchesType = IsModInFilter(ModFilter, CustomLabelFilter, mod); var isVisible = nameMatchesFilter && modMatchesType && authorMatchesFilter && abstractMatchesFilter; return isVisible; } - public int CountModsByFilter(GUIModFilter filter) + public int CountModsByFilter(GUIModFilter filter, ModuleLabel label = null) { if (filter == GUIModFilter.All) { // Don't check each one return Modules.Count; } - return Modules.Count(m => IsModInFilter(filter, m)); + return Modules.Count(m => IsModInFilter(filter, label, m)); } /// @@ -865,6 +887,14 @@ private DataGridViewRow MakeRow(GUIMod mod, List changes, bool hideEp { DataGridViewRow item = new DataGridViewRow() {Tag = mod}; + Color? myColor = ModuleLabels.Labels.FirstOrDefault( + l => l.ModuleIdentifiers.Contains(mod.Identifier) + )?.Color; + if (myColor.HasValue) + { + item.DefaultCellStyle.BackColor = myColor.Value; + } + ModChange myChange = changes?.FindLast((ModChange ch) => ch.Mod.Equals(mod)); var selecting = mod.IsInstallable() @@ -902,7 +932,7 @@ private DataGridViewRow MakeRow(GUIMod mod, List changes, bool hideEp Value = "-" }; - var replacing = IsModInFilter(GUIModFilter.Replaceable, mod) + var replacing = IsModInFilter(GUIModFilter.Replaceable, null, mod) ? (DataGridViewCell) new DataGridViewCheckBoxCell() { Value = myChange == null ? false @@ -953,6 +983,27 @@ private DataGridViewRow MakeRow(GUIMod mod, List changes, bool hideEp return item; } + /// + /// Update the color and visible state of the given row + /// after it has been added to or removed from a label group + /// + /// The mod that needs an update + public void ReapplyLabels(GUIMod mod) + { + DataGridViewRow row; + if (full_list_of_mod_rows.TryGetValue(mod.Identifier, out row)) + { + Color? myColor = ModuleLabels.Labels + .FirstOrDefault(l => l.ModuleIdentifiers.Contains(mod.Identifier)) + ?.Color; + if (myColor.HasValue) + { + row.DefaultCellStyle.BackColor = myColor.Value; + } + row.Visible = IsVisible(mod); + } + } + /// /// Returns a version string shorn of any leading epoch as delimited by a single colon /// @@ -993,8 +1044,18 @@ private bool IsAbstractInDescriptionFilter(GUIMod mod) || mod.SearchableDescription.IndexOf(sanitisedModDescriptionFilter, StringComparison.InvariantCultureIgnoreCase) != -1; } - private static bool IsModInFilter(GUIModFilter filter, GUIMod m) + private static bool IsModInFilter(GUIModFilter filter, ModuleLabel label, GUIMod m) { + if (filter != GUIModFilter.CustomLabel) + { + // "Hide" labels apply to all non-custom filters + if (Main.Instance.mainModList.ModuleLabels.Labels + .Where(l => l.Hide) + .Any(l => l.ModuleIdentifiers.Contains(m.Identifier))) + { + return false; + } + } switch (filter) { case GUIModFilter.Compatible: return !m.IsIncompatible; @@ -1007,6 +1068,7 @@ private static bool IsModInFilter(GUIModFilter filter, GUIMod m) case GUIModFilter.Incompatible: return m.IsIncompatible; case GUIModFilter.Replaceable: return m.IsInstalled && m.HasReplacement; case GUIModFilter.All: return true; + case GUIModFilter.CustomLabel: return label?.ModuleIdentifiers?.Contains(m.Identifier) ?? false; default: throw new Kraken(string.Format(Properties.Resources.MainModListUnknownFilter, filter)); } } diff --git a/GUI/Properties/Resources.Designer.cs b/GUI/Properties/Resources.Designer.cs index 86572f7698..187712930c 100644 --- a/GUI/Properties/Resources.Designer.cs +++ b/GUI/Properties/Resources.Designer.cs @@ -745,5 +745,68 @@ internal static string UtilCopyLink { internal static string StatusInstanceLabelText { get { return (string)(ResourceManager.GetObject("StatusInstanceLabelText", resourceCulture)); } } + internal static string ModuleLabelListFavourites { + get { return (string)(ResourceManager.GetObject("ModuleLabelListFavourites", resourceCulture)); } + } + internal static string ModuleLabelListHidden { + get { return (string)(ResourceManager.GetObject("ModuleLabelListHidden", resourceCulture)); } + } + internal static string ModuleLabelListGlobal { + get { return (string)(ResourceManager.GetObject("ModuleLabelListGlobal", resourceCulture)); } + } + internal static string EditLabelsDialogConfirmDelete { + get { return (string)(ResourceManager.GetObject("EditLabelsDialogConfirmDelete", resourceCulture)); } + } + internal static string EditLabelsDialogSavePrompt { + get { return (string)(ResourceManager.GetObject("EditLabelsDialogSavePrompt", resourceCulture)); } + } + internal static string EditLabelsDialogNoRecord { + get { return (string)(ResourceManager.GetObject("EditLabelsDialogNoRecord", resourceCulture)); } + } + internal static string EditLabelsDialogNameRequired { + get { return (string)(ResourceManager.GetObject("EditLabelsDialogNameRequired", resourceCulture)); } + } + internal static string EditLabelsDialogAlreadyExists { + get { return (string)(ResourceManager.GetObject("EditLabelsDialogAlreadyExists", resourceCulture)); } + } + internal static string EditLabelsDialogDelete { + get { return (string)(ResourceManager.GetObject("EditLabelsDialogDelete", resourceCulture)); } + } + internal static string EditLabelsDialogCancel { + get { return (string)(ResourceManager.GetObject("EditLabelsDialogCancel", resourceCulture)); } + } + internal static string EditLabelsDialogSave { + get { return (string)(ResourceManager.GetObject("EditLabelsDialogSave", resourceCulture)); } + } + internal static string EditLabelsDialogDiscard { + get { return (string)(ResourceManager.GetObject("EditLabelsDialogDiscard", resourceCulture)); } + } + internal static string MainChangesetWarningInstallingHidden { + get { return (string)(ResourceManager.GetObject("MainChangesetWarningInstallingHidden", resourceCulture)); } + } + internal static string EditLabelsToolTipName { + get { return (string)(ResourceManager.GetObject("EditLabelsToolTipName", resourceCulture)); } + } + internal static string EditLabelsToolTipColor { + get { return (string)(ResourceManager.GetObject("EditLabelsToolTipColor", resourceCulture)); } + } + internal static string EditLabelsToolTipInstance { + get { return (string)(ResourceManager.GetObject("EditLabelsToolTipInstance", resourceCulture)); } + } + internal static string EditLabelsToolTipHide { + get { return (string)(ResourceManager.GetObject("EditLabelsToolTipHide", resourceCulture)); } + } + internal static string EditLabelsToolTipNotifyOnChanges { + get { return (string)(ResourceManager.GetObject("EditLabelsToolTipNotifyOnChanges", resourceCulture)); } + } + internal static string EditLabelsToolTipRemoveOnChanges { + get { return (string)(ResourceManager.GetObject("EditLabelsToolTipRemoveOnChanges", resourceCulture)); } + } + internal static string EditLabelsToolTipAlertOnInstall { + get { return (string)(ResourceManager.GetObject("EditLabelsToolTipAlertOnInstall", resourceCulture)); } + } + internal static string EditLabelsToolTipRemoveOnInstall { + get { return (string)(ResourceManager.GetObject("EditLabelsToolTipRemoveOnInstall", resourceCulture)); } + } } } diff --git a/GUI/Properties/Resources.de-DE.resx b/GUI/Properties/Resources.de-DE.resx index f2dddfb932..f238f24d62 100644 --- a/GUI/Properties/Resources.de-DE.resx +++ b/GUI/Properties/Resources.de-DE.resx @@ -314,4 +314,25 @@ Wenn du auf Nein klickst, siehst du diese Nachricht nicht mehr. &Linkadresse kopieren Spielinstanz: {0} (KSP {1}) + Favoriten + Versteckt + Global + Möchten Sie {0} wirklich löschen? Dies kann nicht rückgängig gemacht werden! + Änderungen speichern? + Es wird kein Datensatz bearbeitet! + Name ist erforderlich! + {0} existiert bereits in {1}! + Löschen + Stornieren + Speichern + Verwerfen + WARNUNG: INSTALLIEREN DES VERSTECKTEN MODULS ({0}) + The label will appear in the Labels menu under this name, must be unique per install + Zeilen für Module mit dieser Bezeichnung werden mit dieser Hintergrundfarbe gezeichnet + Die Instanz, für die dieses Label verfügbar ist, muss für alle leer gelassen werden + Wenn diese Option aktiviert ist, werden Module mit dieser Bezeichnung vor Standardfiltern verborgen + Wenn diese Option aktiviert ist, wird eine Benachrichtigung angezeigt, wenn dieses Modul von inkompatibel zu kompatibel wechselt + Wenn diese Option aktiviert ist, wird ein Modul, das von inkompatibel zu kompatibel wechselt, von diesem Label entfernt + Wenn diese Option aktiviert ist, werden Sie auf dem Bildschirm zum Festlegen von Änderungen benachrichtigt, wenn dieser Mod installiert wird + Wenn diese Option aktiviert ist, werden Module von diesem Etikett entfernt, wenn sie installiert sind diff --git a/GUI/Properties/Resources.en-US.resx b/GUI/Properties/Resources.en-US.resx index 86d9ad30bb..68f858fcf9 100644 --- a/GUI/Properties/Resources.en-US.resx +++ b/GUI/Properties/Resources.en-US.resx @@ -119,4 +119,5 @@ CKAN favorites list (*.ckan) + Favorites diff --git a/GUI/Properties/Resources.resx b/GUI/Properties/Resources.resx index a937de51d5..91a8cdea1c 100644 --- a/GUI/Properties/Resources.resx +++ b/GUI/Properties/Resources.resx @@ -333,4 +333,25 @@ Can't update automatically, because ckan.exe is read-only or we are not allowed Do you want to allow CKAN to do this? If you click no you won't see this message again. &Copy link address Game instance: {0} (KSP {1}) + Favourites + Hidden + Global + Are you sure you want to delete {0}? This can't be undone! + Save changes? + No record being edited! + Name is required! + {0} already exists in {1}! + Delete + Cancel + Save + Discard + WARNING: INSTALLING HIDDEN MODULE ({0}) + The label will appear in the Labels menu under this name, must be unique per install + Rows for modules with this label will be drawn with this background color + The instance for which this label is available, leave blank for all + If checked, modules with this label will be hidden from standard filters + If checked, a notification will be displayed if this module changes from incompatible to compatible + If checked, a module that changes from incompatible to compatible will be removed from this label + If checked, the change set screen will alert you if this mod is about to be installed + If checked, modules will be removed from this label if they are installed