//
// Copyright (c) PlaceholderCompany. All rights reserved.
//
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using System.Xml.Serialization;
namespace GeoSigma.SigmaDrawerUtil
{
public class ConfigItem
{
public ConfigItem()
{
}
///
/// Initializes a new instance of the class.
///
/// The item caption.
/// The item name.
/// The item value.
/// The item order.
public ConfigItem(string itemName, string itemCaption, object itemValue, int itemOrder = -1)
{
ItemCaption = itemCaption;
ItemName = itemName;
ItemValue = itemValue;
ItemOrder = itemOrder;
}
///
/// 配置名称显示
///
[XmlAttribute]
public string ItemCaption { get; set; }
///
/// 配置名称
///
[XmlAttribute]
public string ItemName { get; set; }
///
/// 配置值
///
public object ItemValue { get; set; }
[XmlAttribute]
public int ItemOrder { get; set; } = -1;
}
///
/// The config item.
///
public class ConfigNode
{
///
/// 配置分类
///
[XmlAttribute]
public string Name { get; set; }
///
/// 配置分类显示
///
[XmlAttribute]
public string Caption { get; set; }
//[XmlElement]
//public List ConfigNodes { get; set; }
[XmlAttribute]
public int DisplayOrder { get; set; } = 0;
[XmlElement]
public CustomProperties ConfigItems { get; set; } = new CustomProperties();
///
/// Initializes a new instance of the class.
///
public ConfigNode()
{
//ConfigNodes = new List();
}
[XmlAttribute]
public bool Display { get; set; } = true;
///
/// Initializes a new instance of the class.
///
/// The config type.
/// The config name.
/// 是否显示
public ConfigNode(string name, string caption, bool display)
: base()
{
Name = name;
Caption = caption;
this.Display = display;
}
public ConfigNode Clone()
{
ConfigNode node = new ConfigNode(this.Name, this.Caption, this.Display);
foreach (CustomProperty property in this.ConfigItems)
{
node.AddItem(property.Clone());
}
return node;
}
///
/// Adds the item.
///
/// The item.
public void AddItem(CustomProperty item)
{
ConfigItems.Add(item);
if (item.ItemOrder <= 0)
{
item.ItemOrder = ConfigItems.Count - 1;
}
}
}
public delegate void ConfigChangedEventHandler(CustomProperty property, string nodeName);
public class DrawerConfig
{
public ConfigChangedEventHandler ConfigChangedEvent;
[XmlIgnore]
public string FileName; //INI文件名
private string configFile;
[XmlElement("ConfigNodes")]
public List ConfigNodes { get; set; } = new List();
//string path = System.IO.Path.Combine(Application.StartupPath,"pos.ini");
///
/// 添加新节点.
///
/// The new node.
public void AddNode(ConfigNode newNode)
{
ConfigNodes.Add(newNode);
}
///
/// Finds the config value.
///
/// The config name.
/// An object.
public CustomProperty FindConfigValue(string configName)
{
IEnumerable propFind = ConfigNodes.Select(node =>
{
CustomProperty prop = node.ConfigItems.FirstOrDefault(it => it.Name.Equals(configName));
return prop;
})
.Where(it => it != null);
if (propFind != null)
{
CustomProperty prop = propFind.ElementAt(0);
return prop;
}
return null;
}
///
/// Finds the config value.
///
/// The node name.
/// The config name.
/// The default value.
/// A T.
public T FindConfigValue(string nodeName, string configName, T defaultValue)
{
ConfigNode node = ConfigNodes.FirstOrDefault(it => it.Name.Equals(nodeName));
if (node == null)
{
return defaultValue;
}
CustomProperty prop = node.ConfigItems.FirstOrDefault(it => it.Name.Equals(configName));
if (prop == null)
{
return defaultValue;
}
return (T)prop.Value;
}
public bool SetConfigValue(string nodeName, string configName, T value)
{
CustomProperty prop = ConfigNodes.FirstOrDefault(it => it.Name == nodeName)
?.ConfigItems
.FirstOrDefault(it => it.Name == configName);
if (prop == null)
{
Console.WriteLine($"未找到配置项: {nodeName}/{configName}");
return false;
}
prop.Value = value;
return true;
}
//声明读写INI文件的API函数
[DllImport("kernel32")]
private static extern bool WritePrivateProfileString(string section, string key, string val, string filePath);
[DllImport("kernel32")]
private static extern int GetPrivateProfileString(string section, string key, string def, byte[] retVal, int size, string filePath);
//public string GetValue(string key)
//{
// if (configData.Count <= 0)
// return null;
// else if (configData.ContainsKey(key))
// return configData[key].ToString();
// else
// return null;
//}
//public void SetValue(string key, string value)
//{
// if (configData.ContainsKey(key))
// configData[key] = value;
// else
// configData.Add(key, value);
//}
//public void Save()
//{
// StreamWriter writer = new StreamWriter(fullFileName, false, Encoding.Default);
// IDictionaryEnumerator enu = configData.GetEnumerator();
// while (enu.MoveNext())
// {
// if (enu.Key.ToString().StartsWith(";"))
// writer.WriteLine(enu.Value);
// else
// writer.WriteLine(enu.Key + "=" + enu.Value);
// }
// writer.Close();
//}
//类的构造函数,传递INI文件名
///
/// Prevents a default instance of the class from being created.
///
private DrawerConfig()
{
var path = StartupPath;
if (string.IsNullOrEmpty(path))
{
path = System.AppDomain.CurrentDomain.BaseDirectory;
}
var strFileName = path + "\\Sigma.config";
FileInfo fileInfo = new FileInfo(strFileName);
// 必须是完全路径,不能是相对路径
FileName = fileInfo.FullName;
configFile = Path.Combine(path, "KevConfig.xml");
ConfigFile = configFile;
}
private static DrawerConfig instance;
private static string s_startupPath = string.Empty;
///
/// Gets or sets 程序启动目录.
///
public static string StartupPath
{
get => s_startupPath;
set { s_startupPath = value; }
}
public static string ConfigFile { get; set; }
///
/// Gets or sets the instance.
///
public static DrawerConfig Instance
{
get
{
if (instance == null)
{
instance = new DrawerConfig();
if (instance.Open() == false)
{
ConfigNode node = new ConfigNode("RecentFiles", "最近打开的文件", false);
node.ConfigItems.Add(new CustomProperty("FileNumbers", null, "记录数量", 8, typeof(int), "记录数量", false));
node.ConfigItems.Add(new CustomProperty("FileName", null, "上次打开的文件", @"c:\temp\某地区射层层深度构造图.dfd", typeof(string), null, false));
ConfigNode nodeTheme = new ConfigNode("Theme", "界面主题", false);
nodeTheme.ConfigItems.Add(new CustomProperty("Version", null, "主题名称", "WeifenLuo.WinFormsUI.Docking.VS2013LightTheme", typeof(string)));
ConfigNode nodeDisplay = new ConfigNode("Display", "显示", true);
nodeDisplay.ConfigItems.Add(new CustomProperty("ZoomMode", null, "缩放模式", 1, typeof(int)));
nodeDisplay.ConfigItems.Add(new CustomProperty("Precision", null, "保留小数", -1, typeof(int)));
ConfigNode nodeGridSet = new ConfigNode("GridSet", "绘图网格", true);
nodeGridSet.ConfigItems.Add(new CustomProperty("ShowGrid", null, "显示网格", false, typeof(bool), "是否显示网格", true, false, 0));
nodeGridSet.ConfigItems.Add(new CustomProperty("X", null, "X", 0.5d, typeof(double), "X方向间距", true, false, 1));
nodeGridSet.ConfigItems.Add(new CustomProperty("Y", null, "Y", 0.5d, typeof(double), "Y方向间距", true, false, 2));
ConfigNode nodeIntersection = new ConfigNode("Extension", "区域充填", true);
nodeIntersection.ConfigItems.Add(new CustomProperty("Length", null, "延伸长度", 100d, typeof(double)));
ConfigNode nodeMesh = new ConfigNode("MeshDisplay", "曲面网格", true);
nodeMesh.ConfigItems.Add(new CustomProperty("SmoothTeeth", null, "消除锯齿", false, typeof(bool)));
nodeMesh.ConfigItems.Add(new CustomProperty("LoopColor", null, "循环颜色", false, typeof(bool)));
ConfigNode nodeSelectRange = new ConfigNode("SelectRange", "选择范围", true);
nodeSelectRange.ConfigItems.Add(new CustomProperty("Extension", null, "相交面积百分比", 100d, typeof(double)));
ConfigNode nodeAreaTrade = new ConfigNode("AreaTrade", "面积计算", true);
nodeAreaTrade.ConfigItems.Add(new CustomProperty("CaculateMethod", null, "面积权衡方式", 0, typeof(int)));
ConfigNode debugNode = new ConfigNode("Debug", "调试", true);
debugNode.ConfigItems.Add(new CustomProperty("Enable", null, "启用", false, typeof(bool)));
instance.ConfigNodes.AddRange(new ConfigNode[]
{
node
, nodeTheme
, nodeDisplay
, nodeGridSet
, nodeIntersection
, nodeMesh
, nodeSelectRange
, nodeAreaTrade
, debugNode,
});
instance.Save();
instance.SetDefaultEditor(instance.ConfigNodes);
}
}
return instance;
}
set
{
instance = value;
}
}
///
/// 写出统计结果
///
public void Save()
{
string strFile = this.configFile;
if (!File.Exists(strFile))
{
File.Create(strFile).Close();
}
using (StreamWriter writer = new StreamWriter(strFile))
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(List));
XmlSerializerNamespaces nameSpace = new XmlSerializerNamespaces();
nameSpace.Add(string.Empty, string.Empty);
xmlSerializer.Serialize(writer, this.ConfigNodes, nameSpace);
}
}
///
/// 打开配置文件.
///
/// 是否成功
public bool Open()
{
string strFile = this.configFile;
Trace.WriteLine(strFile);
if (string.IsNullOrEmpty(strFile) || !File.Exists(strFile))
{
return false;
}
try
{
using (StreamReader reader = new StreamReader(strFile))
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(List));
this.ConfigNodes = xmlSerializer.Deserialize(reader) as List;
SetDefaultEditor(this.ConfigNodes);
}
}
catch (Exception ex)
{
return false;
}
return true;
}
public DrawerConfig Clone()
{
DrawerConfig config = new DrawerConfig();
foreach (ConfigNode node in this.ConfigNodes)
{
config.ConfigNodes.Add(node.Clone());
}
return config;
}
private void SetDefaultEditor(List nodes)
{
for (int i = 0; i < nodes.Count; i++)
{
for (int j = 0; j < nodes[i].ConfigItems.Count; j++)
{
CustomProperty prop = nodes[i].ConfigItems[j];
prop.PropertyType = prop.Value.GetType();
if (prop.Name.Equals("ZoomMode"))
{
prop.Converter = new StringComboItemConvert("左上,居中");
}
else if (prop.Name.Equals("CaculateMethod"))
{
prop.Converter = new StringComboItemConvert("积分方式,等值线区域");
}
else if (prop.PropertyType == typeof(bool))
{
prop.Converter = new CustomBooleanConverter();
}
else
{
prop.Converter = null;
}
prop.ParentName = nodes[i].Name;
prop.PropertyChanged -= Prop_PropertyChanged;
prop.PropertyChanged += Prop_PropertyChanged;
//if (prop.PropertyChanged == null)
//{
// prop.PropertyChanged += (object sender, System.ComponentModel.PropertyChangedEventArgs e) =>
// {
// ConfigChangedEvent?.Invoke(prop, nodes[i].Name);
// };
//}
}
}
}
private void Prop_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
PropertyChangedEventArgsEx ex = e as PropertyChangedEventArgsEx;
if (ex != null)
{
ConfigChangedEvent?.Invoke(sender as CustomProperty, ex.ParentName);
}
}
//写INI文件
public void WriteString(string section, string ident, string value)
{
if (!WritePrivateProfileString(section, ident, value, FileName))
{
throw (new ApplicationException("写Ini文件出错"));
}
}
//读取INI文件指定
public string ReadString(string section, string ident, string @default)
{
byte[] buffer = new byte[65535];
int bufLen = GetPrivateProfileString(section, ident, @default, buffer, buffer.GetUpperBound(0), FileName);
//必须设定0(系统默认的代码页)的编码方式,否则无法支持中文
string s = Encoding.GetEncoding(0).GetString(buffer);
s = s.Substring(0, bufLen);
return s.Trim();
}
////读整数
//public int ReadInteger(string section, string ident, int @default)
//{
// string intStr = ReadString(section, ident, Convert.ToString(@default));
// try
// {
// return Convert.ToInt32(intStr);
// }
// catch (Exception ex)
// {
// Console.WriteLine(ex.Message);
// return @default;
// }
//}
//写整数
public void WriteInteger(string section, string ident, int value)
{
WriteString(section, ident, value.ToString());
}
////读布尔
//public bool ReadBool(string section, string ident, bool @default)
//{
// try
// {
// return Convert.ToBoolean(ReadString(section, ident, Convert.ToString(@default)));
// }
// catch (Exception ex)
// {
// Console.WriteLine(ex.Message);
// return @default;
// }
//}
//写Bool
public void WriteBool(string section, string ident, bool value)
{
WriteString(section, ident, Convert.ToString(value));
}
//从Ini文件中,将指定的Section名称中的所有Ident添加到列表中
public void ReadSection(string section, StringCollection idents)
{
Byte[] Buffer = new Byte[16384];
//Idents.Clear();
int bufLen = GetPrivateProfileString(section, null, null, Buffer, Buffer.GetUpperBound(0), FileName);
//对Section进行解析
GetStringsFromBuffer(Buffer, bufLen, idents);
}
private void GetStringsFromBuffer(Byte[] buffer, int bufLen, StringCollection strings)
{
strings.Clear();
if (bufLen != 0)
{
int start = 0;
for (int i = 0; i < bufLen; i++)
{
if ((buffer[i] == 0) && ((i - start) > 0))
{
String s = Encoding.GetEncoding(0).GetString(buffer, start, i - start);
strings.Add(s);
start = i + 1;
}
}
}
}
//从Ini文件中,读取所有的Sections的名称
public void ReadSections(StringCollection sectionList)
{
//Note:必须得用Bytes来实现,StringBuilder只能取到第一个Section
byte[] Buffer = new byte[65535];
int bufLen = 0;
bufLen = GetPrivateProfileString(null, null, null, Buffer,
Buffer.GetUpperBound(0), FileName);
GetStringsFromBuffer(Buffer, bufLen, sectionList);
}
////读取指定的Section的所有Value到列表中
//public void ReadSectionValues(string section, NameValueCollection values)
//{
// StringCollection KeyList = new StringCollection();
// ReadSection(section, KeyList);
// values.Clear();
// foreach (string key in KeyList)
// {
// values.Add(key, ReadString(section, key, string.Empty));
// }
//}
//清除某个Section
public void EraseSection(string section)
{
if (!WritePrivateProfileString(section, null, null, FileName))
{
throw (new ApplicationException("无法清除Ini文件中的Section"));
}
}
//删除某个Section下的键
public void DeleteKey(string section, string ident)
{
WritePrivateProfileString(section, ident, null, FileName);
}
//Note:对于Win9X,来说需要实现UpdateFile方法将缓冲中的数据写入文件
//在Win NT, 2000和XP上,都是直接写文件,没有缓冲,所以,无须实现UpdateFile
//执行完对Ini文件的修改之后,应该调用本方法更新缓冲区。
public void UpdateFile()
{
WritePrivateProfileString(null, null, null, FileName);
}
//检查某个Section下的某个键值是否存在
public bool ValueExists(string section, string ident)
{
StringCollection Idents = new StringCollection();
ReadSection(section, Idents);
return Idents.IndexOf(ident) > -1;
}
//确保资源的释放
~DrawerConfig()
{
//UpdateFile();
}
}
}