Files
minecraft-modpack-updater/ModpackUpdater.Apps.Manager/Ui/MainForm.cs
2025-11-12 14:29:31 +01:00

652 lines
23 KiB
C#

using ModpackUpdater.Apps.Manager.Api.Model;
using ModpackUpdater.Apps.Manager.Api.Plugins.Features;
using ModpackUpdater.Apps.Manager.Api.Plugins.Params;
using ModpackUpdater.Apps.Manager.LangRes;
using ModpackUpdater.Apps.Manager.Settings;
using Pilz.Features;
using Pilz.UI.Symbols;
using Pilz.UI.WinForms.Extensions;
using Pilz.UI.WinForms.Telerik.Features;
using Telerik.WinControls;
using Telerik.WinControls.UI;
namespace ModpackUpdater.Apps.Manager.Ui;
public partial class MainForm : RadForm, IMainApi
{
private record RecentFilesItemTag(WorkspaceConfig Config, WorkspaceFeature Feature);
private record WorkspaceTag(IWorkspace Workspace, WorkspaceFeature Feature);
private bool loadingMainView;
private WorkspaceTag? wsInfo;
private InstallAction? tempAction;
Form IMainApi.MainWindow => this;
IWorkspace? IMainApi.CurWorkspace => wsInfo?.Workspace;
public IActionSetInfos? CurActionSet => radTreeView_Sets.SelectedNode?.Tag as IActionSetInfos;
public MainForm()
{
InitializeComponent();
radMenuItem_Workspace.SvgImage = AppGlobals.Symbols.GetSvgImage(AppSymbols.workspace, SymbolSize.Small);
radMenuItem_WorkspacePreferences.SvgImage = AppGlobals.Symbols.GetSvgImage(AppSymbols.settings, SymbolSize.Small);
radMenuItem_SaveWorkspace.SvgImage = AppGlobals.Symbols.GetSvgImage(AppSymbols.save, SymbolSize.Small);
//radMenuItem_OpenNewWorkspace.SvgImage = AppGlobals.Symbols.GetSvgImage(AppSymbols.new_window, SymbolSize.Small);
//radMenuItem_RecentWorkspaces.SvgImage = AppGlobals.Symbols.GetSvgImage(AppSymbols.time_machine, SymbolSize.Small);
radMenuItem_Updates.SvgImage = AppGlobals.Symbols.GetSvgImage(AppSymbols.update_done, SymbolSize.Small);
radMenuItem_CreateUpdate.SvgImage = AppGlobals.Symbols.GetSvgImage(AppSymbols.add, SymbolSize.Small);
radMenuItem_RemoveUpdate.SvgImage = AppGlobals.Symbols.GetSvgImage(AppSymbols.remove, SymbolSize.Small);
radMenuItem_Tools.SvgImage = AppGlobals.Symbols.GetSvgImage(AppSymbols.tools, SymbolSize.Small);
radMenuItem_SaveWorkspace.Shortcuts.Add(new(Keys.Control, Keys.S));
PluginFeatureController.Instance.Features.Get(FeatureTypes.Workspace).InsertItemsTo(radMenuItem_Workspace.Items,
customClickHandler: RadMenuItem_OpenNewWorkspace_Click,
insertPrioSplitters: true,
customDefault: radMenuItem_Workspace.Items.IndexOf(radMenuHeaderItem_NewWorkspace) + 1);
PluginFeatureController.Instance.Functions.Get(FeatureTypes.Tools).InsertItemsTo(radMenuItem_Tools.Items,
customClickHandler: RadMenuItem_ToolsItem_Click,
insertPrioSplitters: true);
}
private void LoadRecentWorkspaces()
{
var settings = Program.Settings.Get<WorkspaceSettings>();
var startIndex = radMenuItem_Workspace.Items.IndexOf(radMenuHeaderItem_RecentWorkspaces) + 1;
foreach (var item in radMenuItem_Workspace.Items.Where(n => n.Tag is RecentFilesItemTag).ToArray())
radMenuItem_Workspace.Items.Remove(item);
foreach (var config in settings.Workspaces)
{
if (PluginFeatureController.Instance.Features.Get(FeatureTypes.Workspace).OfType<WorkspaceFeature>().FirstOrDefault(n => n.Identifier == config.ProviderId) is not WorkspaceFeature feature)
continue;
var item = new RadMenuItem
{
Text = config.DisplayText,
Tag = new RecentFilesItemTag(config, feature),
SvgImage = feature.Icon as RadSvgImage,
};
item.Click += RadMenuItem_OpenRecentWorkspace_Click;
radMenuItem_Workspace.Items.Insert(startIndex++, item);
}
}
private void AddToRecentFiles(IWorkspace workspace)
{
var settings = Program.Settings.Get<WorkspaceSettings>();
settings.Workspaces.Remove(workspace.Config);
settings.Workspaces.Insert(0, workspace.Config);
while (settings.Workspaces.Count > 20)
settings.Workspaces.RemoveAt(20);
}
private async Task LoadNewWorkspace(IWorkspace? workspace, WorkspaceFeature feature)
{
if (workspace is null)
return;
if (workspace != wsInfo?.Workspace)
wsInfo = new(workspace, feature);
AddToRecentFiles(workspace);
Invoke(LoadRecentWorkspaces);
radWaitingBar_Updates.StartWaiting();
if (!await workspace.Load())
{
radWaitingBar_Updates.StopWaiting();
return;
}
Invoke(LoadWorkspace);
}
private void LoadWorkspace()
{
if (wsInfo?.Workspace.Config is null || wsInfo.Workspace.InstallInfos is null || wsInfo.Workspace.UpdateInfos is null)
return;
radWaitingBar_Updates.StartWaiting();
Text = wsInfo.Workspace.Config.DisplayText;
radTreeView_Sets.BeginUpdate();
radTreeView_Sets.Nodes.Clear();
AddUpdateItem(wsInfo.Workspace.InstallInfos);
var nodeUpdates = new RadTreeNode
{
Text = "Updates",
Name = "updates",
SvgImage = AppGlobals.Symbols.GetSvgImage(AppSymbols.update_done, SymbolSize.Small),
};
wsInfo.Workspace.UpdateInfos.Updates.ForEach(n => AddUpdateItem(n, nodeUpdates.Nodes));
radTreeView_Sets.Nodes.Add(nodeUpdates);
radTreeView_Sets.EndUpdate();
radWaitingBar_Updates.StopWaiting();
}
private RadTreeNode AddUpdateItem(IActionSetInfos infos)
{
return AddUpdateItem(infos, radTreeView_Sets.Nodes);
}
private RadTreeNode AddUpdateItem(IActionSetInfos infos, RadTreeNodeCollection parent)
{
var item = CreateUpdateItem(infos);
parent.Add(item);
return item;
}
private RadTreeNode InsertUpdateItem(IActionSetInfos infos)
{
var item = CreateUpdateItem(infos);
var nodeUpdates = radTreeView_Sets.Nodes["updates"];
nodeUpdates.Nodes.Insert(Math.Min(1, nodeUpdates.Nodes.Count), item);
return item;
}
private RadTreeNode CreateUpdateItem(IActionSetInfos infos)
{
var item = new RadTreeNode();
UpdateUpdateItem(item, infos);
return item;
}
private void UpdateUpdateItem(RadTreeNode item)
{
if (item.Tag is IActionSetInfos infos)
UpdateUpdateItem(item, infos);
}
private void SaveActionsSet()
{
if (loadingMainView || CurActionSet is not IActionSetInfos infos)
return;
if (!Version.TryParse(radTextBoxControl_Version.Text.Trim(), out Version? version))
version = new Version("1.0.0.0");
infos.Version = version;
infos.IsPublic = radCheckBox_IsPublic.Checked;
UpdateUpdateItem(radTreeView_Sets.SelectedNode);
}
private void UpdateUpdateItem(RadTreeNode item, IActionSetInfos infos)
{
if (item.Tag != infos)
item.Tag = infos;
if (infos is UpdateInfo)
item.Text = string.Format(GeneralLangRes.Node_Update, infos.Version?.ToString() ?? "?");
else if (infos is InstallInfos)
item.Text = string.Format(GeneralLangRes.Node_Install, infos.Version?.ToString() ?? "?");
else
item.Text = infos.Version.ToString();
item.SvgImage = AppGlobals.Symbols.GetSvgImage(infos.IsPublic ? AppSymbols.eye : AppSymbols.invisible, SymbolSize.Small);
}
public void UpdateItem(IActionSetInfos actionSetInfos)
{
RadTreeNode? item = null;
var nodeUpdates = radTreeView_Sets.Nodes["updates"];
foreach (var iitem in nodeUpdates.Nodes)
{
if (item == null && iitem.Value == actionSetInfos)
item = iitem;
}
if (item == null)
InsertUpdateItem(actionSetInfos);
else if (wsInfo?.Workspace.UpdateInfos != null && !wsInfo.Workspace.UpdateInfos.Updates.Contains(actionSetInfos))
item.Remove();
else
UpdateUpdateItem(item);
}
public void UpdateItem(InstallAction action)
{
foreach (var row in radGridView_Actions.Rows)
{
if (row.Tag == action)
UpdateActionRow(row);
}
}
private void LoadMainView()
{
loadingMainView = true;
tableLayoutPanel_ActionSet.Visible = false;
tableLayoutPanel_ActionSetInfo.Visible = false;
if (CurActionSet is IActionSet set)
{
if (set is IActionSetInfos infos)
{
radTextBoxControl_Version.Text = infos.Version?.ToString();
radCheckBox_IsPublic.Checked = infos.IsPublic;
tableLayoutPanel_ActionSetInfo.Visible = true;
}
tableLayoutPanel_ActionSet.Visible = true;
LoadActionSet(set);
}
loadingMainView = false;
}
private void LoadActionSet(IActionSet infos)
{
radGridView_Actions.BeginUpdate();
radGridView_Actions.Rows.Clear();
radGridView_Actions.Columns.Clear();
// Add columns
radGridView_Actions.Columns.AddRange([
new GridViewTextBoxColumn
{
Name = "id",
HeaderText = ActionsListLangRes.Col_Id,
Width = 150,
IsVisible = infos is not UpdateInfo,
IsPinned = true,
},
new GridViewTextBoxColumn
{
Name = "name",
HeaderText = ActionsListLangRes.Col_Name,
Width = 150,
IsVisible = infos is not UpdateInfo,
},
new GridViewTextBoxColumn
{
Name = "inherit",
HeaderText = ActionsListLangRes.Col_InheritFrom,
Width = 150,
IsVisible = infos is UpdateInfo,
IsPinned = true,
},
new GridViewComboBoxColumn
{
Name = "utype",
HeaderText = ActionsListLangRes.Col_UpdateType,
Width = 150,
DataSource = Enum.GetValues<UpdateActionType>(),
IsVisible = infos is UpdateInfo,
},
new GridViewComboBoxColumn
{
Name = "side",
HeaderText = ActionsListLangRes.Col_Side,
Width = 100,
DataSource = Enum.GetValues<Side>(),
},
new GridViewCheckBoxColumn
{
Name = "isextra",
HeaderText = ActionsListLangRes.Col_IsExtra,
Width = 50,
},
new GridViewCheckBoxColumn
{
Name = "iszip",
HeaderText = ActionsListLangRes.Col_IsZip,
Width = 50,
},
new GridViewCheckBoxColumn
{
Name = "isdir",
HeaderText = ActionsListLangRes.Col_IsDir,
Width = 50,
IsVisible = infos is UpdateInfo,
},
new GridViewTextBoxColumn
{
Name = "destpath",
HeaderText = ActionsListLangRes.Col_DestPath,
Width = 250,
},
new GridViewComboBoxColumn
{
Name = "srctype",
HeaderText = ActionsListLangRes.Col_SrcType,
Width = 150,
DataSource = Enum.GetValues<SourceType>(),
},
new GridViewTextBoxColumn
{
Name = "srcowner",
HeaderText = ActionsListLangRes.Col_SrcOwner,
Width = 150,
},
new GridViewTextBoxColumn
{
Name = "srcname",
HeaderText = ActionsListLangRes.Col_SrcName,
Width = 150,
},
new GridViewTextBoxColumn
{
Name = "srcregex",
HeaderText = ActionsListLangRes.Col_SrcRegEx,
Width = 200,
},
new GridViewTextBoxColumn
{
Name = "srctag",
HeaderText = ActionsListLangRes.Col_SrcTag,
Width = 150,
},
new GridViewTextBoxColumn
{
Name = "srcurl",
HeaderText = ActionsListLangRes.Col_SrcUrl,
Width = 350,
},
new GridViewTextBoxColumn
{
Name = "zippath",
HeaderText = ActionsListLangRes.Col_ZipPath,
Width = 200,
},
new GridViewTextBoxColumn
{
Name = "srcpath",
HeaderText = ActionsListLangRes.Col_SrcPath,
Width = 250,
IsVisible = infos is UpdateInfo,
},
new GridViewTextBoxColumn
{
Name = "website",
HeaderText = ActionsListLangRes.Col_Website,
Width = 350,
},
]);
// Add rows
foreach (var action in infos.Actions)
{
var row = radGridView_Actions.Rows.AddNew();
row.Tag = action;
UpdateActionRow(row);
}
radGridView_Actions.EndUpdate();
}
private void UpdateActionRow(GridViewRowInfo row)
{
if (row.Tag is not InstallAction action)
return;
row.Cells["id"].Value = action.Id;
row.Cells["name"].Value = action.Name;
row.Cells["iszip"].Value = action.IsZip;
row.Cells["zippath"].Value = action.ZipPath;
row.Cells["destpath"].Value = action.DestPath;
row.Cells["srcurl"].Value = action.SourceUrl;
row.Cells["srctype"].Value = action.SourceType;
row.Cells["srcowner"].Value = action.SourceOwner;
row.Cells["srcname"].Value = action.SourceName;
row.Cells["srcregex"].Value = action.SourceRegex;
row.Cells["srctag"].Value = action.SourceTag;
row.Cells["side"].Value = action.Side;
row.Cells["isextra"].Value = action.IsExtra;
row.Cells["website"].Value = action.Website;
if (action is not UpdateAction uaction)
return;
row.Cells["inherit"].Value = uaction.InheritFrom; // TODO: Find inherit action and put it in here!
row.Cells["utype"].Value = uaction.Type;
row.Cells["srcpath"].Value = uaction.SrcPath;
row.Cells["isdir"].Value = uaction.IsDirectory;
}
private void Form1_Load(object sender, EventArgs e)
{
LoadRecentWorkspaces();
}
private async void RadMenuItem_OpenNewWorkspace_Click(object? sender, EventArgs e)
{
if (sender is RadMenuItem item && item.Tag is WorkspaceFeature feature)
{
var ws = wsInfo?.Workspace;
if (feature.Configure(ws))
await LoadNewWorkspace(ws, feature);
}
}
private async void RadMenuItem_OpenRecentWorkspace_Click(object? sender, EventArgs e)
{
if (sender is RadMenuItem item && item.Tag is RecentFilesItemTag tag && tag.Feature.CreateFromConfig(tag.Config) is IWorkspace workspace)
await LoadNewWorkspace(workspace, tag.Feature);
}
private async void RadMenuItem_WorkspacePreferences_Click(object sender, EventArgs e)
{
if (wsInfo != null)
{
var ws = wsInfo.Workspace;
if (wsInfo.Feature.Configure(ws))
await LoadNewWorkspace(ws, wsInfo.Feature);
}
}
private void RadMenuItem_SaveWorkspace_Click(object sender, EventArgs e)
{
wsInfo?.Workspace.Save();
}
private void RadMenuItem_ToolsItem_Click(object? sender, EventArgs e)
{
if (sender is RadMenuItem item && item.Tag is PluginFunction func)
func.Execute(new MainApiParameters(this));
}
private void RadTreeView_Sets_SelectedNodeChanged(object sender, RadTreeViewEventArgs e)
{
LoadMainView();
}
private void RadGridView_Actions_CellFormatting(object sender, CellFormattingEventArgs e)
{
//var cellElement = e.CellElement;
//var cellInfo = e.Row.Cells[e.Column.Name];
//if (e.Column.Name == "srctype" && cellInfo?.Value is string sourceTypeStr && Enum.Parse<SourceType>(sourceTypeStr) is SourceType sourceType)
//{
// cellElement.SvgImage = sourceType switch
// {
// SourceType.DirectLink => AppGlobals.Symbols.GetSvgImage(AppSymbols.link, SymbolSize.Small),
// SourceType.GitHub => AppGlobals.Symbols.GetSvgImage(AppSymbols.github, SymbolSize.Small),
// _ => null,
// };
// cellElement.DrawImage = cellElement.SvgImage != null;
// cellElement.TextImageRelation = TextImageRelation.ImageBeforeText;
// cellElement.ImageAlignment = ContentAlignment.MiddleLeft;
//}
//else
//{
// cellElement.ResetValue(LightVisualElement.SvgImageProperty, ValueResetFlags.Local);
// cellElement.ResetValue(LightVisualElement.DrawImageProperty, ValueResetFlags.Local);
// cellElement.ResetValue(LightVisualElement.TextImageRelationProperty, ValueResetFlags.Local);
// cellElement.ResetValue(LightVisualElement.ImageAlignmentProperty, ValueResetFlags.Local);
//}
}
private void RadGridView_Actions_CellValueChanged(object sender, GridViewCellEventArgs e)
{
if (e.Row is null)
return;
if (e.Row.Tag is not InstallAction action)
{
if (CurActionSet is UpdateInfo)
action = tempAction ??= new UpdateAction();
else if (CurActionSet is InstallInfos)
action = tempAction ??= new InstallAction();
else
return;
}
var uaction = action as UpdateAction;
var newValue = e.Row.Cells[e.Column.Name].Value;
var colName = e.Column.Name;
if (newValue is bool valueBool)
{
switch (colName)
{
case "iszip":
action.IsZip = valueBool;
break;
case "isextra":
action.IsExtra = valueBool;
break;
case "isdir":
if (uaction is not null)
uaction.IsDirectory = valueBool;
break;
}
}
else
{
var valueStr = newValue as string ?? string.Empty;
var valueNullStr = valueStr.Nullify();
switch (colName)
{
case "id":
action.Id = valueNullStr;
break;
case "name":
action.Name = valueNullStr;
break;
case "zippath":
action.ZipPath = valueNullStr;
break;
case "destpath":
action.DestPath = valueNullStr;
break;
case "srcurl":
action.SourceUrl = valueNullStr;
break;
case "srctype":
action.SourceType = Enum.Parse<SourceType>(valueStr);
break;
case "srcowner":
action.SourceOwner = valueNullStr;
break;
case "srcname":
action.SourceName = valueNullStr;
break;
case "srcregex":
action.SourceRegex = valueNullStr;
break;
case "srctag":
action.SourceTag = valueNullStr;
break;
case "website":
action.Website = valueNullStr;
break;
case "side":
action.Side = Enum.Parse<Side>(valueStr);
break;
case "inherit":
if (uaction is not null)
uaction.InheritFrom = valueNullStr;
break;
case "utype":
if (uaction is not null)
uaction.Type = Enum.Parse<UpdateActionType>(valueStr);
break;
case "srcpath":
if (uaction is not null)
uaction.SrcPath = valueNullStr;
break;
}
}
}
private void RadMenuItem_Updates_DropDownOpening(object sender, System.ComponentModel.CancelEventArgs e)
{
radMenuItem_RemoveUpdate.Enabled = radTreeView_Sets.SelectedNode?.Tag is UpdateInfo;
}
private void RadMenuItem_CreateUpdate_Click(object sender, EventArgs e)
{
if (wsInfo?.Workspace.UpdateInfos is null)
return;
var infos = new UpdateInfo
{
Version = wsInfo.Workspace.InstallInfos?.Version,
};
wsInfo.Workspace.UpdateInfos.Updates.Insert(0, infos);
InsertUpdateItem(infos);
}
private void RadMenuItem_RemoveUpdate_Click(object sender, EventArgs e)
{
if (radTreeView_Sets.SelectedNode?.Tag is UpdateInfo infos && wsInfo?.Workspace.UpdateInfos is not null
&& RadMessageBox.Show(MsgBoxLangRes.RemoveUpdate, MsgBoxLangRes.RemoveUpdate_Title, MessageBoxButtons.YesNo, RadMessageIcon.Exclamation).IsYes())
{
wsInfo.Workspace.UpdateInfos.Updates.Remove(infos);
radTreeView_Sets.SelectedNode.Remove();
}
}
private void RadGridView_Actions_UserAddedRow(object sender, GridViewRowEventArgs e)
{
if (tempAction is UpdateAction uaction && CurActionSet is UpdateInfo uinfo)
uinfo.Actions.Add(uaction);
else if (tempAction is InstallAction iaction && CurActionSet is InstallInfos iinfo)
iinfo.Actions.Add(iaction);
tempAction = null;
}
private void RadGridView_Actions_UserDeletingRow(object sender, GridViewRowCancelEventArgs e)
{
foreach (var row in e.Rows)
{
if (row.Tag is UpdateAction uaction && CurActionSet is UpdateInfo uinfo)
uinfo.Actions.Remove(uaction);
else if (row.Tag is InstallAction iaction && CurActionSet is InstallInfos iinfo)
iinfo.Actions.Remove(iaction);
}
}
private void RadGridView_Actions_ContextMenuOpening(object sender, ContextMenuOpeningEventArgs e)
{
if (e.ContextMenuProvider is GridDataCellElement)
{
e.ContextMenu.Items.Add(new RadMenuSeparatorItem());
PluginFeatureController.Instance.Functions.Get(FeatureTypes.ActionsContextMenu).InsertItemsTo(e.ContextMenu.Items, customClickHandler: RadMenuItem_ToolsItem_Click, insertPrioSplitters: true);
}
}
private void RadTextBoxControl1_TextChanged(object sender, EventArgs e)
{
SaveActionsSet();
}
private void RadCheckBox1_ToggleStateChanged(object sender, StateChangedEventArgs args)
{
SaveActionsSet();
}
}