|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Text;
using System.Text.RegularExpressions;
namespace System.Windows.Forms;
/// <summary>
/// Helper class used by ToolStripManager that implements most of the logic to save out and apply
/// settings for toolstrips on a form.
/// </summary>
internal partial class ToolStripSettingsManager
{
private readonly Form _form;
private readonly string _formKey;
internal ToolStripSettingsManager(Form owner, string formKey)
{
_form = owner;
_formKey = formKey;
}
internal void Load()
{
List<SettingsStub> savedToolStripSettingsObjects = [];
List<ToolStrip> toolStripControls = [];
FindControls(true, _form.Controls, toolStripControls);
foreach (ToolStrip toolStrip in toolStripControls)
{
if (!string.IsNullOrEmpty(toolStrip.Name))
{
ToolStripSettings toolStripSettings = new(GetSettingsKey(toolStrip));
// Check if we have settings saved out for this toolstrip. If so, add it to our apply list.
if (!toolStripSettings.IsDefault)
{
savedToolStripSettingsObjects.Add(new SettingsStub(toolStripSettings));
}
}
}
ApplySettings(savedToolStripSettingsObjects);
}
internal void Save()
{
List<ToolStrip> toolStripControls = [];
FindControls(true, _form.Controls, toolStripControls);
foreach (ToolStrip toolStrip in toolStripControls)
{
if (!string.IsNullOrEmpty(toolStrip.Name))
{
ToolStripSettings toolStripSettings = new(GetSettingsKey(toolStrip));
SettingsStub stub = new(toolStrip);
toolStripSettings.ItemOrder = stub.ItemOrder;
toolStripSettings.Name = stub.Name;
toolStripSettings.Location = stub.Location;
toolStripSettings.Size = stub.Size;
toolStripSettings.ToolStripPanelName = stub.ToolStripPanelName;
toolStripSettings.Visible = stub.Visible;
toolStripSettings.Save();
}
}
}
internal static string GetItemOrder(ToolStrip toolStrip)
{
if (toolStrip.Items.Count == 0)
{
return string.Empty;
}
StringBuilder itemNames = new(toolStrip.Items.Count);
for (int i = 0; i < toolStrip.Items.Count; i++)
{
itemNames.Append(toolStrip.Items[i].Name ?? "null");
itemNames.Append(',');
}
return itemNames.ToString(0, itemNames.Length - 1);
}
private void ApplySettings(List<SettingsStub> toolStripSettingsToApply)
{
if (toolStripSettingsToApply.Count == 0)
{
return;
}
SuspendAllLayout(_form);
// iterate through all the toolstrips and build up a hash of where the items
// are right now.
Dictionary<string, ToolStrip> itemLocationHash = BuildItemOriginationHash();
// build up a hash of where we want the ToolStrips to go
Dictionary<object, List<SettingsStub>> toolStripPanelDestinationHash = [];
foreach (SettingsStub toolStripSettings in toolStripSettingsToApply)
{
object? destinationPanel = !string.IsNullOrEmpty(toolStripSettings.ToolStripPanelName) ? toolStripSettings.ToolStripPanelName : null;
if (destinationPanel is null)
{
// Not in a panel.
if (!string.IsNullOrEmpty(toolStripSettings.Name))
{
// apply the toolstrip settings.
ToolStrip? toolStrip = ToolStripManager.FindToolStrip(_form, toolStripSettings.Name);
ApplyToolStripSettings(toolStrip, toolStripSettings, itemLocationHash);
}
}
else
{
// This toolStrip is in a ToolStripPanel. We will process it below.
if (!toolStripPanelDestinationHash.TryGetValue(destinationPanel, out List<SettingsStub>? value))
{
value = [];
toolStripPanelDestinationHash[destinationPanel] = value;
}
value.Add(toolStripSettings);
}
}
// Build up a list of the toolstrippanels to party on.
List<ToolStripPanel> toolStripPanels = [];
FindControls(true, _form.Controls, toolStripPanels);
foreach (ToolStripPanel toolStripPanel in toolStripPanels)
{
// Set all the controls to visible false.
foreach (Control c in toolStripPanel.Controls)
{
c.Visible = false;
}
string toolStripPanelName = toolStripPanel.Name;
// Handle the ToolStripPanels inside a ToolStripContainer
if (string.IsNullOrEmpty(toolStripPanelName) && toolStripPanel.Parent is ToolStripContainer && !string.IsNullOrEmpty(toolStripPanel.Parent.Name))
{
toolStripPanelName = $"{toolStripPanel.Parent.Name}.{toolStripPanel.Dock}";
}
toolStripPanel.BeginInit();
// get the associated toolstrips for this panel
if (toolStripPanelDestinationHash.TryGetValue(toolStripPanelName, out List<SettingsStub>? stubSettings))
{
foreach (SettingsStub settings in stubSettings)
{
if (!string.IsNullOrEmpty(settings.Name))
{
// apply the toolstrip settings.
ToolStrip? toolStrip = ToolStripManager.FindToolStrip(_form, settings.Name);
ApplyToolStripSettings(toolStrip, settings, itemLocationHash);
toolStripPanel.Join(toolStrip!, settings.Location);
}
}
}
toolStripPanel.EndInit();
}
ResumeAllLayout(_form, true);
}
private static void ApplyToolStripSettings(ToolStrip? toolStrip, SettingsStub settings, Dictionary<string, ToolStrip> itemLocationHash)
{
if (toolStrip is null)
{
return;
}
toolStrip.Visible = settings.Visible;
toolStrip.Size = settings.Size;
// Apply the item order changes.
string? itemNames = settings.ItemOrder;
if (!string.IsNullOrEmpty(itemNames))
{
string[] keys = itemNames.Split(',');
Regex r = ContiguousNonWhitespace();
// Shuffle items according to string.
for (int i = 0; ((i < toolStrip.Items.Count) && (i < keys.Length)); i++)
{
Match match = r.Match(keys[i]);
if (match.Success)
{
string key = match.Value;
if (!string.IsNullOrEmpty(key) && itemLocationHash.TryGetValue(key, out ToolStrip? value))
{
toolStrip.Items.Insert(i, value.Items[key]!);
}
}
}
}
}
[GeneratedRegex("\\S+")]
private static partial Regex ContiguousNonWhitespace();
private Dictionary<string, ToolStrip> BuildItemOriginationHash()
{
Dictionary<string, ToolStrip> itemLocationHash = [];
List<ToolStrip> toolStripControls = [];
FindControls(true, _form.Controls, toolStripControls);
foreach (ToolStrip toolStrip in toolStripControls)
{
foreach (ToolStripItem item in toolStrip.Items)
{
if (!string.IsNullOrEmpty(item.Name))
{
Debug.Assert(!itemLocationHash.ContainsKey(item.Name), "WARNING: ToolStripItem name not unique.");
itemLocationHash[item.Name] = toolStrip;
}
}
}
return itemLocationHash;
}
private void FindControls<T>(bool searchAllChildren, Control.ControlCollection controlsToLookIn, List<T> foundControls)
where T : Control
{
try
{
// Perform breadth first search - as it's likely people will want controls belonging
// to the same parent close to each other.
for (int i = 0; i < controlsToLookIn.Count; i++)
{
if (controlsToLookIn[i] is null)
{
continue;
}
if (controlsToLookIn[i] is T control)
{
foundControls.Add(control);
}
}
// Optional recursive search for controls in child collections.
if (searchAllChildren)
{
for (int i = 0; i < controlsToLookIn.Count; i++)
{
if (controlsToLookIn[i] is null or Form)
{
continue;
}
if ((controlsToLookIn[i].Controls is not null) && controlsToLookIn[i].Controls.Count > 0)
{
// If it has a valid child collection, append those results to our collection.
FindControls(searchAllChildren, controlsToLookIn[i].Controls, foundControls);
}
}
}
}
catch (Exception e) when (!e.IsCriticalException())
{
}
}
private string GetSettingsKey(ToolStrip toolStrip)
{
if (toolStrip is not null)
{
return $"{_formKey}.{toolStrip.Name}";
}
return string.Empty;
}
private static void ResumeAllLayout(Control start, bool performLayout)
{
Control.ControlCollection controlsCollection = start.Controls;
for (int i = 0; i < controlsCollection.Count; i++)
{
ResumeAllLayout(controlsCollection[i], performLayout);
}
start.ResumeLayout(performLayout);
}
private static void SuspendAllLayout(Control start)
{
start.SuspendLayout();
Control.ControlCollection controlsCollection = start.Controls;
for (int i = 0; i < controlsCollection.Count; i++)
{
SuspendAllLayout(controlsCollection[i]);
}
}
}
|