I18NCommander/I18N Commander/UI WinForms/Components/SectionTree.cs

184 lines
6.9 KiB
C#
Raw Normal View History

2022-07-09 20:23:10 +00:00
using DataModel.Database.Common;
2022-07-09 13:06:49 +00:00
using Microsoft.Extensions.DependencyInjection;
using Processor;
using UI_WinForms.Dialogs;
using UI_WinForms.Resources;
namespace UI_WinForms.Components;
public partial class SectionTree : UserControl
{
private readonly DataContext db;
public SectionTree()
{
this.InitializeComponent();
// Get the DI context from the main form:
this.db = Program.SERVICE_PROVIDER.GetService<DataContext>()!;
// Dispose of the context when the control is disposed:
this.Disposed += (_, _) => this.db.Dispose();
// Create an image list from a resource:
var imgList = new ImageList();
imgList.ImageSize = new Size(45, 45);
imgList.ColorDepth = ColorDepth.Depth32Bit;
imgList.Images.Add(Icons.icons8_documents_folder_512);
// Set the image list to the tree view:
this.treeView.ImageList = imgList;
// Subscribe to the load event:
this.Load += this.LoadNodes;
2022-07-09 13:06:49 +00:00
}
private async void LoadNodes(object? sender, EventArgs e)
2022-07-09 13:06:49 +00:00
{
// A dictionary to cache all known tree nodes:
var treeNodes = new Dictionary<string, TreeNode>();
// Get the max. depth of the tree:
var maxDepth = await SectionProcessor.GetDepth(this.db);
// Store nodes, where we cannot find the parents:
var missingParents = new List<TreeNode>();
// Populate the tree view out of the database, layer by layer:
for (var i = 0; i <= maxDepth; i++)
{
await foreach (var section in SectionProcessor.LoadLayer(this.db, i))
{
// Create the tree node:
var node = new TreeNode
{
Name = section.DataKey, // [sic] name is the key
Text = section.Name,
StateImageIndex = 1,
};
// Cache the node:
treeNodes.Add(section.DataKey, node);
// Is this a root node?
if (section.Depth is 0)
// Set the root node:
this.treeView.Nodes.Add(node);
// Otherwise, attach this section to its parent node:
else
{
// Get the parent from our cache within O(1):
treeNodes.TryGetValue(section.Parent?.DataKey ?? string.Empty, out var parent);
// If the parent node is not found, skip this section:
if (parent is null)
{
missingParents.Add(node);
continue;
}
// Add the node to the parent:
parent.Nodes.Add(node);
}
}
}
// If we found any missing parents, show a dialog:
if (missingParents.Any())
{
MessageBox.Show($"In {missingParents.Count} case(s) we could not found the matching parent. We added these nodes to a special root node, though.", "Parent not found", MessageBoxButtons.OK, MessageBoxIcon.Error);
// Create a root node for all missing parents:
var rootMissedParents = new TreeNode
{
Name = "MISSING_PARENTS",
Text = "Missing Parents",
StateImageIndex = 1,
};
// Add the root node to the tree:
this.treeView.Nodes.Add(rootMissedParents);
// Add all missing parents to the root node:
foreach (var node in missingParents)
rootMissedParents.Nodes.Add(node);
}
2022-07-09 20:23:10 +00:00
// Expand the tree:
this.treeView.ExpandAll();
2022-07-09 13:06:49 +00:00
}
private async void buttonAdd_Click(object sender, EventArgs e)
{
var result = InputDialog.Show(new InputDialog.Options(
Message: "Please type the desired section name.",
Title: "Add a section",
Placeholder: "My next section",
ShowQuestionCheckbox: true,
QuestionCheckboxText: "Add a root node (i.e. ignoring the selected node)"
));
2022-07-09 13:06:49 +00:00
if(result.DialogResult == DialogResult.Cancel)
return;
var addRootNode = result.AnswerToQuestion;
2022-07-09 13:06:49 +00:00
// Get the currently selected section as parent:
var selectedNode = this.treeView.SelectedNode;
// Add the new section to the database:
var addedSection = await SectionProcessor.AddSection(this.db, result.Text, addRootNode ? null : selectedNode?.Name);
2022-07-09 13:06:49 +00:00
// Add the new section to the tree control:
var node = new TreeNode
{
Name = addedSection.DataKey, // [sic] name is the key
Text = addedSection.Name,
StateImageIndex = 1,
};
if(!addRootNode && selectedNode is not null)
2022-07-09 13:06:49 +00:00
selectedNode.Nodes.Add(node);
else
this.treeView.Nodes.Add(node);
// Ensure, that the added node is visible and gets the focus:
node.EnsureVisible();
this.treeView.SelectedNode = node;
}
private async void buttonRemove_Click(object sender, EventArgs e)
{
// Get the currently selected section, which will be removed:
var selectedNode = this.treeView.SelectedNode;
// Get the number of children:
// (notice, that the node's name is its key)
var numberChildren = await SectionProcessor.NumberChildren(this.db, selectedNode.Name);
// Ask the user, if he really wants to remove the section:
if(MessageBox.Show(numberChildren > 0 ? $"Are you sure, you want to remove the section '{selectedNode.Text}', its {numberChildren} children and so on?" : $"Are you sure, you want to remove the section '{selectedNode.Text}'?", "Remove section", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.No)
return;
// Remove the section from the database:
// (notice, that the node's name is its key)
await SectionProcessor.RemoveSection(this.db, selectedNode.Name);
// Remove all nodes from the tree control:
this.treeView.Nodes.Clear();
// Reload the tree:
this.LoadNodes(this, EventArgs.Empty);
}
private void treeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
// Get the currently selected section:
var selectedNode = this.treeView.SelectedNode;
// If the selected node is not null, enable the remove button:
this.buttonRemove.Enabled = selectedNode is not null;
}
2022-07-09 13:06:49 +00:00
}