From 9313ec42ba8ae0e95f87e3bd973a18431f90810d Mon Sep 17 00:00:00 2001 From: BlubbFish Date: Sun, 15 Nov 2015 23:38:57 +0000 Subject: [PATCH] =?UTF-8?q?Utils=20hinzugef=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Utils.sln | 20 +++ Utils/CmdArgs.cs | 201 +++++++++++++++++++++++++++++++ Utils/FileLogger.cs | 47 ++++++++ Utils/InIReader.cs | 198 ++++++++++++++++++++++++++++++ Utils/OwnController.cs | 21 ++++ Utils/OwnModel.cs | 36 ++++++ Utils/OwnObject.cs | 72 +++++++++++ Utils/OwnView.cs | 24 ++++ Utils/Properties/AssemblyInfo.cs | 36 ++++++ Utils/Utils.csproj | 60 +++++++++ Utils/bin/Release/Utils.dll | Bin 0 -> 15872 bytes 11 files changed, 715 insertions(+) create mode 100644 Utils.sln create mode 100644 Utils/CmdArgs.cs create mode 100644 Utils/FileLogger.cs create mode 100644 Utils/InIReader.cs create mode 100644 Utils/OwnController.cs create mode 100644 Utils/OwnModel.cs create mode 100644 Utils/OwnObject.cs create mode 100644 Utils/OwnView.cs create mode 100644 Utils/Properties/AssemblyInfo.cs create mode 100644 Utils/Utils.csproj create mode 100644 Utils/bin/Release/Utils.dll diff --git a/Utils.sln b/Utils.sln new file mode 100644 index 0000000..eaf0824 --- /dev/null +++ b/Utils.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Utils", "Utils\Utils.csproj", "{FAC8CE64-BF13-4ECE-8097-AEB5DD060098}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FAC8CE64-BF13-4ECE-8097-AEB5DD060098}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FAC8CE64-BF13-4ECE-8097-AEB5DD060098}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FAC8CE64-BF13-4ECE-8097-AEB5DD060098}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FAC8CE64-BF13-4ECE-8097-AEB5DD060098}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Utils/CmdArgs.cs b/Utils/CmdArgs.cs new file mode 100644 index 0000000..0c52719 --- /dev/null +++ b/Utils/CmdArgs.cs @@ -0,0 +1,201 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BlubbFish.Utils +{ + public class CmdArgs + { + public enum ArgLength + { + Single, + Touple + } + #region Classes + public class VaildArguments + { + public VaildArguments(ArgLength length, bool required) + { + this.Required = required; + this.Length = length; + } + public VaildArguments(ArgLength length) + { + this.Required = false; + this.Length = length; + } + + public ArgLength Length { get; private set; } + public bool Required { get; private set; } + } + private class ArgTouple + { + public ArgTouple(string type, string data) + { + this.type = type; + this.data = data; + } + public ArgTouple(string type) + { + this.type = type; + } + public string type { get; private set; } + public string data { get; private set; } + + internal void setData(string data) + { + if (data != "") + this.data = data; + } + } + #endregion + private string[] args; + private List argList; + private Dictionary argsPosible = new Dictionary(); + private static CmdArgs instances = null; + private bool isSetArguments = false; + + private CmdArgs() + { + } + + /// + /// Gibt eine Instanz der Klasse zurück + /// + /// Klasse + public static CmdArgs getInstance() + { + if (instances == null) + { + instances = new CmdArgs(); + } + return instances; + } + + /// + /// Übernimmt die Argumente für die Klasse + /// + /// Mögliche Komandozeilenargumente + /// Tatsächliche Komandozeilenargumente + public void setArguments(Dictionary arguments, string[] args) + { + this.args = args; + if (!this.isSetArguments) + { + this.isSetArguments = true; + this.argsPosible = arguments; + this.Init(); + } + } + + private void Init() + { + this.argList = new List(); + for (int i = 0; i < this.args.Length; i++) + { + if (this.argsPosible.Keys.Contains(args[i])) + { + ArgTouple arg = new ArgTouple(args[i]); + if (argsPosible[args[i]].Length == ArgLength.Touple) + { + if (args.Length > i + 1) + { + arg.setData(args[++i]); + } + else + { + throw new ArgumentException(); + } + } + this.argList.Add(arg); + } + } + } + + /// + /// Menge der angegebenen Komandozeilen-Argumente + /// + /// Menge + public int GetArgsLength() + { + return this.argList.Count; + } + + /// + /// Gibt zurück ob ein Argument angegeben wurde + /// + /// Name des Arguments + /// true wenn angegeben + public bool HasArgumentType(string name) + { + foreach (ArgTouple t in this.argList) + { + if (t.type == name) + return true; + } + return false; + } + + /// + /// Gibt den Inhalt des angegeben Arguments zurück, nur bei zweiteiligen Argumenten möglich + /// + /// Name des Arguments + /// Inhalt des Arguments oder ArgumentNullException + public string GetArgumentData(string name) + { + foreach (ArgTouple t in this.argList) + { + if (t.type == name && t.data != null) + return t.data; + else + { + throw new ArgumentNullException(); + } + } + return null; + } + + public bool HasAllRequiredArguments() + { + foreach (KeyValuePair item in this.argsPosible) + { + if (item.Value.Required && !this.HasArgumentType(item.Key)) + { + return false; + } + } + return true; + } + + public string getUsageList(string name) + { + string ret = "Usage: "+name+" Parameter\nParameter:\n"; + string req =""; + string opt = ""; + foreach (KeyValuePair item in this.argsPosible) + { + if (item.Value.Required) + { + req += item.Key+" "+((item.Value.Length == ArgLength.Touple)?" [data]\n":"\n"); + } + } + if (req != "") + { + ret += "Benötigte Parameter:\n" + req; + } + foreach (KeyValuePair item in this.argsPosible) + { + if (!item.Value.Required) + { + opt += item.Key + " " + ((item.Value.Length == ArgLength.Touple) ? " [data]\n" : "\n"); + } + } + if (opt != "") + { + ret += "Optionale Parameter:\n" + opt; + } + return ret; + } + } +} diff --git a/Utils/FileLogger.cs b/Utils/FileLogger.cs new file mode 100644 index 0000000..6157d7d --- /dev/null +++ b/Utils/FileLogger.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; + +namespace BlubbFish.Utils +{ + public class FileLogger + { + private static Dictionary instances = new Dictionary(); + private StreamWriter file; + private FileLogger(string filename, bool append) + { + if (!File.Exists(filename)) + { + string folder = Path.GetDirectoryName(Path.GetFullPath(filename)); + if (!Directory.Exists(folder)) + { + Directory.CreateDirectory(folder); + } + } + this.file = new StreamWriter(filename, append, Encoding.UTF8); + this.file.AutoFlush = true; + } + public static FileLogger getInstance(string filename, bool append) + { + if (!instances.Keys.Contains(filename)) + { + instances.Add(filename, new FileLogger(filename, append)); + } + return instances[filename]; + } + + public void setArray(string[] text) + { + this.file.Write(String.Join(file.NewLine, text) + file.NewLine); + this.file.Flush(); + } + + public void setLine(string text) + { + this.file.WriteLine(text); + this.file.Flush(); + } + } +} diff --git a/Utils/InIReader.cs b/Utils/InIReader.cs new file mode 100644 index 0000000..fc87deb --- /dev/null +++ b/Utils/InIReader.cs @@ -0,0 +1,198 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace BlubbFish.Utils +{ + public class InIReader + { + private Dictionary> cont; + private FileSystemWatcher k = new FileSystemWatcher(Directory.GetCurrentDirectory(), "*.ini"); + private string filename; + + private static Dictionary instances = new Dictionary(); + + private InIReader(string filename) + { + this.filename = filename; + k.Changed += new FileSystemEventHandler(this.readAgain); + loadFile(); + } + + public static InIReader getInstance(string filename) + { + if (!instances.Keys.Contains(filename)) + { + instances.Add(filename, new InIReader(filename)); + } + return instances[filename]; + } + + private void readAgain(object sender, EventArgs e) + { + this.loadFile(); + } + + private void loadFile() + { + this.cont = new Dictionary>(); + StreamReader file = new StreamReader(this.filename); + List buf = new List(); + string fline = ""; + while (fline != null) + { + fline = file.ReadLine(); + if (fline != null && fline.Length > 0 && fline.Substring(0,1) != ";") + buf.Add(fline); + } + file.Close(); + Dictionary sub = new Dictionary(); + string cap = ""; + foreach (string line in buf) + { + Match match = Regex.Match(line, @"^\[[a-zA-Z0-9\-_ ]+\]\w*$", RegexOptions.IgnoreCase); + if (match.Success) + { + if (sub.Count != 0 && cap != "") + { + this.cont.Add(cap, sub); + } + cap = line; + sub = new Dictionary(); + } + else + { + if (line != "" && cap != "") + { + string key = line.Substring(0, line.IndexOf('=')); + string value = line.Substring(line.IndexOf('=') + 1); + sub.Add(key, value); + } + } + } + if (sub.Count != 0 && cap != "") + { + this.cont.Add(cap, sub); + } + } + + public List getSections() + { + return cont.Keys.ToList(); + } + + public String getValue(String section, String key) + { + if (!section.StartsWith("[")) + { + section = "[" + section + "]"; + } + if (cont.Keys.Contains(section)) + { + if (cont[section].Keys.Contains(key)) + { + return cont[section][key]; + } + } + return null; + } + + + public void SetValue(string section, string key, string value) + { + if (!section.StartsWith("[")) + { + section = "[" + section + "]"; + } + if (cont.Keys.Contains(section)) + { + if (cont[section].Keys.Contains(key)) + { + cont[section][key] = value; + } + else + { + cont[section].Add(key, value); + } + } + else + { + Dictionary sub = new Dictionary(); + sub.Add(key, value); + cont.Add(section, sub); + } + this.changed(); + } + + private void changed() + { + k.Changed -= null; + saveSettings(); + loadFile(); + k.Changed += new FileSystemEventHandler(this.readAgain); + } + + private void saveSettings() + { + StreamWriter file = new StreamWriter(this.filename); + file.BaseStream.SetLength(0); + file.BaseStream.Flush(); + file.BaseStream.Seek(0, SeekOrigin.Begin); + foreach (KeyValuePair> cap in this.cont) + { + file.WriteLine(cap.Key); + foreach (KeyValuePair sub in cap.Value) + { + file.WriteLine(sub.Key + "=" + sub.Value); + } + file.WriteLine(); + } + file.Flush(); + file.Close(); + } + + /// + /// Fügt eine neue Sektion in der Ini-Datei ein. + /// + /// Sektionsname + /// true if added, false if error + public bool addSection(string name) + { + if (!name.StartsWith("[")) + { + name = "[" + name + "]"; + } + if (this.cont.Keys.Contains(name)) + { + return false; + } + this.cont.Add(name, new Dictionary()); + this.changed(); + return true; + } + + /// + /// Löscht eine Sektion inklusive Unterpunkte aus der Ini-Datei. + /// + /// Sektionsname + /// true if removed, false if error + public bool removeSection(string name) + { + if (!name.StartsWith("[")) + { + name = "[" + name + "]"; + } + if (!this.cont.Keys.Contains(name)) + { + return false; + } + this.cont.Remove(name); + this.changed(); + return false; + } + } +} diff --git a/Utils/OwnController.cs b/Utils/OwnController.cs new file mode 100644 index 0000000..9a5ac35 --- /dev/null +++ b/Utils/OwnController.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace BlubbFish.Utils +{ + public abstract class OwnController + { + /// + /// Führt den Controller aus. + /// + public void execute() + { + this.init(); + } + abstract protected void init(); + } +} diff --git a/Utils/OwnModel.cs b/Utils/OwnModel.cs new file mode 100644 index 0000000..42c2273 --- /dev/null +++ b/Utils/OwnModel.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BlubbFish.Utils +{ + public abstract class OwnModel where T : class + { + private static readonly Lazy _instance = new Lazy(() => CreateInstanceOfT()); + private List observer = new List(); + public static T Instance + { + get + { + return _instance.Value; + } + } + private static T CreateInstanceOfT() + { + return Activator.CreateInstance(typeof(T), true) as T; + } + + public void setObserver(OwnView tray) + { + this.observer.Add(tray); + tray.update(); + } + protected void update() + { + this.observer.ForEach(delegate(OwnView tray) { tray.update(); }); + } + abstract protected void init(); + } +} diff --git a/Utils/OwnObject.cs b/Utils/OwnObject.cs new file mode 100644 index 0000000..fc884b5 --- /dev/null +++ b/Utils/OwnObject.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BlubbFish.Utils { + abstract public class OwnObject { + private List> loglist = new List>(); + + public delegate void LogEvent(string location, string message, LogLevel level, DateTime date); + public enum LogLevel : int { + Debug = 1, + Notice = 2, + Info = 4, + Warn = 8, + Error = 16 + } + + public event LogEvent eventDebug; + public event LogEvent eventNotice; + public event LogEvent eventInfo; + public event LogEvent eventWarn; + public event LogEvent eventError; + public event LogEvent EventLog; + + /// + /// Get the Complete Log + /// + public List getLog(LogLevel level, bool classNames, bool timeStamps) { + List ret = new List(); + foreach(Tuple t in this.loglist) { + if(t.Item4 >= level) { + ret.Add(logToString(t.Item2, t.Item3, t.Item4, t.Item1, classNames, timeStamps)); + } + } + return ret; + } + + /// + /// Formates a LogMessage to a String + /// + public static string logToString(string location, string message, LogLevel level, DateTime date, bool classNames, bool timeStamps) { + return (timeStamps ? "[" + date.ToString("R") + "]: "+level.ToString()+" " : "") + (classNames ? location + ", " : "") + message; + } + + protected void addLog(string location, string message, LogLevel level) { + this.addLog(location, message, level, DateTime.Now); + } + + protected void addLog(string location, string message, LogLevel level, DateTime date) { + if(eventDebug != null && level >= LogLevel.Debug) { + eventDebug(location, message, level, date); + } + if(eventNotice != null && level >= LogLevel.Notice) { + eventNotice(location, message, level, date); + } + if(eventInfo != null && level >= LogLevel.Info) { + eventInfo(location, message, level, date); + } + if(eventWarn != null && level >= LogLevel.Warn) { + eventWarn(location, message, level, date); + } + if(eventError != null && level >= LogLevel.Error) { + eventError(location, message, level, date); + } + if(EventLog != null) { + EventLog(location, message, level, date); + } + this.loglist.Add(new Tuple(date, location, message, level)); + } + } +} diff --git a/Utils/OwnView.cs b/Utils/OwnView.cs new file mode 100644 index 0000000..4b39e48 --- /dev/null +++ b/Utils/OwnView.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BlubbFish.Utils +{ + public abstract class OwnView + { + /// + /// Called if the Oberver (Model) updates its View + /// + abstract public void update(); + /// + /// Called if view is viewed + /// + abstract protected void init(); + /// + /// Called if Form is Disposed + /// + abstract public void Dispose(); + } +} diff --git a/Utils/Properties/AssemblyInfo.cs b/Utils/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..1ed8460 --- /dev/null +++ b/Utils/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die mit einer Assembly verknüpft sind. +[assembly: AssemblyTitle("Utils")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Utils")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar +// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von +// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest. +[assembly: ComVisible(false)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("6f20376a-5c71-4979-9932-13c105d1c6e6")] + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern +// übernehmen, indem Sie "*" eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Utils/Utils.csproj b/Utils/Utils.csproj new file mode 100644 index 0000000..22e3a26 --- /dev/null +++ b/Utils/Utils.csproj @@ -0,0 +1,60 @@ + + + + + Debug + AnyCPU + {FAC8CE64-BF13-4ECE-8097-AEB5DD060098} + Library + Properties + BlubbFish.Utils + Utils + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Utils/bin/Release/Utils.dll b/Utils/bin/Release/Utils.dll new file mode 100644 index 0000000000000000000000000000000000000000..d11ce7ca29a8b9be6c71d09ddf621bb7fff8e761 GIT binary patch literal 15872 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 If4UL)zwC`n2mk;8 literal 0 HcmV?d00001