diff --git a/MBS.Framework/Application.cs b/MBS.Framework/Application.cs new file mode 100644 index 0000000..26b7ad9 --- /dev/null +++ b/MBS.Framework/Application.cs @@ -0,0 +1,229 @@ +// +// Application.cs +// +// Author: +// Michael Becker +// +// Copyright (c) 2020 Mike Becker's Software +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WAR+RANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +using System.Collections.Generic; + +namespace MBS.Framework +{ + public class Application + { + public static Application Instance { get; set; } = null; + + public Guid ID { get; set; } = Guid.Empty; + public string UniqueName { get; set; } = null; + public string ShortName { get; set; } + public string Title { get; set; } = String.Empty; + public int ExitCode { get; protected set; } = 0; + + public CommandLine CommandLine { get; protected set; } = null; + + public Application() + { + CommandLine = new DefaultCommandLine(); + } + + private Dictionary> _CommandEventHandlers = new Dictionary>(); + public Command.CommandCollection Commands { get; } = new Command.CommandCollection(); + public bool AttachCommandEventHandler(string commandID, EventHandler handler) + { + Command cmd = Commands[commandID]; + if (cmd != null) + { + cmd.Executed += handler; + return true; + } + Console.WriteLine("attempted to attach handler for unknown command '" + commandID + "'"); + + // handle command event handlers attached without a Command instance + if (!_CommandEventHandlers.ContainsKey(commandID)) + { + _CommandEventHandlers.Add(commandID, new List()); + } + if (!_CommandEventHandlers[commandID].Contains(handler)) + { + _CommandEventHandlers[commandID].Add(handler); + } + return false; + } + public void ExecuteCommand(string id, KeyValuePair[] namedParameters = null) + { + Command cmd = Commands[id]; + + // handle command event handlers attached without a Command instance + if (_CommandEventHandlers.ContainsKey(id)) + { + List c = _CommandEventHandlers[id]; + for (int i = 0; i < c.Count; i++) + { + c[i](cmd, new CommandEventArgs(cmd, namedParameters)); + } + return; + } + + // handle command event handlers attached in a context, most recently added first + for (int i = Contexts.Count - 1; i >= 0; i--) + { + if (Contexts[i].ExecuteCommand(id)) + return; + } + + if (cmd == null) + return; + + cmd.Execute(); + } + + protected virtual void InitializeInternal() + { + } + + [System.Diagnostics.DebuggerNonUserCode()] + public void Initialize() + { + if (ShortName == null) + throw new ArgumentException("must specify a ShortName for the application"); + + InitializeInternal(); + } + + protected virtual int StartInternal() + { + return 0; + } + public int Start() + { + int exitCode = StartInternal(); + return exitCode; + } + + // CONTEXTS + + /// + /// Gets a collection of objects representing system, application, user, and custom contexts for settings and other items. + /// + /// A collection of objects representing cpublic for settings and other items. + public Context.ContextCollection Contexts { get; } = new Context.ContextCollection(); + + public ContextChangedEventHandler ContextAdded; + protected virtual void OnContextAdded(ContextChangedEventArgs e) + { + ContextAdded?.Invoke(this, e); + } + + public ContextChangedEventHandler ContextRemoved; + protected virtual void OnContextRemoved(ContextChangedEventArgs e) + { + ContextRemoved?.Invoke(this, e); + } + + /// + /// Handles updating the menus, toolbars, keyboard shortcuts, and other UI elements associated with the application . + /// + internal void AddContext(Context ctx) + { + OnContextAdded(new ContextChangedEventArgs(ctx)); + } + + /// + /// Handles updating the menus, toolbars, keyboard shortcuts, and other UI elements associated with the application . + /// + internal void RemoveContext(Context ctx) + { + OnContextRemoved(new ContextChangedEventArgs(ctx)); + } + + // LOGGING + public void Log(string message) + { + Log(null, 0, message); + } + public void Log(object obj, int lineNumber, string message) + { + if (obj is Type) + { + Console.WriteLine("{0}: {1}", ((Type)obj).FullName, message); + } + else if (obj != null) + { + Console.WriteLine("{0}: {1}", obj.GetType().FullName, message); + } + else + { + Console.WriteLine("{0}", message); + } + } + + public bool Stopping { get; private set; } = false; + + protected virtual void OnStopping(System.ComponentModel.CancelEventArgs e) + { + + } + protected virtual void OnStopped(EventArgs e) + { + + } + + public event System.ComponentModel.CancelEventHandler BeforeShutdown; + protected virtual void OnBeforeShutdown(System.ComponentModel.CancelEventArgs e) + { + BeforeShutdown?.Invoke(this, e); + } + + public event EventHandler Shutdown; + private void OnShutdown(EventArgs e) + { + Shutdown?.Invoke(this, e); + } + + + protected virtual void StopInternal(int exitCode) + { + } + public void Stop(int exitCode = 0) + { + if (Stopping) + return; + + Stopping = true; + + System.ComponentModel.CancelEventArgs ce = new System.ComponentModel.CancelEventArgs(); + OnStopping(ce); + if (ce.Cancel) + return; + + ce = new System.ComponentModel.CancelEventArgs(); + OnBeforeShutdown(ce); + if (ce.Cancel) + { + return; + } + + StopInternal(exitCode); + + OnShutdown(EventArgs.Empty); + + OnStopped(EventArgs.Empty); + Stopping = false; + } + + } +} diff --git a/MBS.Framework/Command.cs b/MBS.Framework/Command.cs new file mode 100644 index 0000000..33f9daf --- /dev/null +++ b/MBS.Framework/Command.cs @@ -0,0 +1,104 @@ +using System; + +namespace MBS.Framework +{ + public class Command + { + public class CommandCollection + : System.Collections.ObjectModel.Collection + { + public Command this[string ID] + { + get + { + foreach (Command command in this) + { + if (command.ID == ID) return command; + } + return null; + } + } + } + + public Command() + { + } + public Command(string id, string title, CommandItem[] items = null) + { + ID = id; + Title = title; + if (items != null) + { + for (int i = 0; i < items.Length; i++) + { + Items.Add(items[i]); + } + } + } + /// + /// Determines whether this command displays as checked. + /// + public bool Checked { get; set; } = false; + /// + /// The ID of the command, used to reference it in . + /// + public string ID { get; set; } = String.Empty; + /// + /// The title of the command (including mnemonic prefix, if applicable). + /// + public string Title { get; set; } = String.Empty; + + private string mvarDefaultCommandID = String.Empty; + public string DefaultCommandID { get { return mvarDefaultCommandID; } set { mvarDefaultCommandID = value; } } + + /// + /// A that represents a predefined, platform-themed command. + /// + public StockType StockType { get; set; } = StockType.None; + + private string mvarImageFileName = String.Empty; + /// + /// The file name of the image to be displayed on the command. + /// + public string ImageFileName { get { return mvarImageFileName; } set { mvarImageFileName = value; } } + + + /// + /// The child s that are contained within this . + /// + public CommandItem.CommandItemCollection Items { get; } = new CommandItem.CommandItemCollection(); + + /// + /// The event that is fired when the command is executed. + /// + public event EventHandler Executed; + + /// + /// Determines whether this is enabled in all s and s + /// that reference it. + /// + /// true if visible; otherwise, false. + public bool Enabled { get; set; } = true; + + /// + /// Determines whether this is visible in all s and s + /// that reference it. + /// + /// true if visible; otherwise, false. + public bool Visible { get; set; } + + /// + /// Executes this . + /// + public void Execute() + { + if (Executed != null) Executed(this, EventArgs.Empty); + } + + public override string ToString() + { + return String.Format("{0} [{1}]", ID, Title); + } + } +} + diff --git a/MBS.Framework/CommandEvent.cs b/MBS.Framework/CommandEvent.cs new file mode 100644 index 0000000..f7ce11f --- /dev/null +++ b/MBS.Framework/CommandEvent.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; + +namespace MBS.Framework +{ + public class CommandEventArgs : EventArgs + { + public Command Command { get; private set; } + + private Dictionary _NamedParameters = new Dictionary(); + public T GetNamedParameter(string key, T defaultValue = default(T)) + { + if (_NamedParameters.ContainsKey(key)) + return (T)_NamedParameters[key]; + return defaultValue; + } + public object GetNamedParameter(string key, object defaultValue = null) + { + if (_NamedParameters.ContainsKey(key)) + return _NamedParameters[key]; + return defaultValue; + } + + + public CommandEventArgs(Command command, KeyValuePair[] namedParameters = null) + { + Command = command; + if (namedParameters != null) + { + for (int i = 0; i < namedParameters.Length; i++) + { + _NamedParameters[namedParameters[i].Key] = namedParameters[i].Value; + } + } + } + } + public delegate void CommandEventHandler(object sender, CommandEventArgs e); +} diff --git a/MBS.Framework/CommandItem.cs b/MBS.Framework/CommandItem.cs new file mode 100644 index 0000000..10b020a --- /dev/null +++ b/MBS.Framework/CommandItem.cs @@ -0,0 +1,55 @@ +using System; + +namespace MBS.Framework +{ + public abstract class CommandItem + { + public string InsertAfterID { get; set; } = null; + public string InsertBeforeID { get; set; } = null; + + public class CommandItemCollection + : System.Collections.ObjectModel.Collection + { + public int IndexOf(string value) + { + for (int i = 0; i < Count; i++) + { + if (this[i] is CommandReferenceCommandItem) + { + if ((this[i] as CommandReferenceCommandItem).CommandID.Equals(value)) + return i; + } + } + return -1; + } + } + } + public class CommandReferenceCommandItem : CommandItem + { + private string mvarCommandID = String.Empty; + public string CommandID { get { return mvarCommandID; } set { mvarCommandID = value; } } + + public CommandReferenceCommandItem(string commandID) + { + mvarCommandID = commandID; + } + } + public class CommandPlaceholderCommandItem : CommandItem + { + private string mvarPlaceholderID = String.Empty; + public string PlaceholderID { get { return mvarPlaceholderID; } set { mvarPlaceholderID = value; } } + + public CommandPlaceholderCommandItem(string placeholderID) + { + mvarPlaceholderID = placeholderID; + } + } + public class SeparatorCommandItem : CommandItem + { + } + public class GroupCommandItem : CommandItem + { + public CommandItemCollection Items { get; } = new CommandItemCollection(); + } +} + diff --git a/MBS.Framework/CommandLine.cs b/MBS.Framework/CommandLine.cs new file mode 100644 index 0000000..95d30b5 --- /dev/null +++ b/MBS.Framework/CommandLine.cs @@ -0,0 +1,50 @@ +// +// CommandLine.cs +// +// Author: +// Mike Becker +// +// Copyright (c) 2019 Mike Becker +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +using System.Collections.Generic; + +namespace MBS.Framework +{ + public abstract class CommandLine + { + /// + /// Gets the original array of arguments. + /// + /// The arguments. + public string[] Arguments { get; private set; } + + /// + /// Gets the list of file names passed on the command line. + /// + /// The file names. + public List FileNames { get; } = new List(); + + public CommandLineOption.CommandLineOptionCollection Options { get; } = new CommandLineOption.CommandLineOptionCollection(); + + protected CommandLine() + { + } + protected internal CommandLine(string[] arguments) + { + this.Arguments = arguments; + } + } +} diff --git a/MBS.Framework/CommandLineOption.cs b/MBS.Framework/CommandLineOption.cs new file mode 100644 index 0000000..44d6059 --- /dev/null +++ b/MBS.Framework/CommandLineOption.cs @@ -0,0 +1,129 @@ +// +// CommandLineOption.cs +// +// Author: +// Mike Becker +// +// Copyright (c) 2019 Mike Becker +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +using System.Collections.Generic; + +namespace MBS.Framework +{ + public class CommandLineOption + { + public class CommandLineOptionCollection + : System.Collections.ObjectModel.Collection + { + private Dictionary _byAbbreviation = new Dictionary(); + private Dictionary _byName = new Dictionary(); + + public bool Contains(char abbreviation) + { + return _byAbbreviation.ContainsKey(abbreviation); + } + public bool Contains(string name) + { + return _byName.ContainsKey(name); + } + + public CommandLineOption this[char abbreviation] + { + get + { + if (_byAbbreviation.ContainsKey(abbreviation)) + return _byAbbreviation[abbreviation]; + return null; + } + } + public CommandLineOption this[string name] + { + get + { + if (_byName.ContainsKey(name)) + return _byName[name]; + return null; + } + } + + protected override void ClearItems() + { + base.ClearItems(); + + _byName.Clear(); + _byAbbreviation.Clear(); + } + protected override void InsertItem(int index, CommandLineOption item) + { + base.InsertItem(index, item); + + if (item.Name != null) + _byName[item.Name] = item; + + if (item.Abbreviation != '\0') + _byAbbreviation[item.Abbreviation] = item; + } + + public CommandLineOption Add(string name, char abbreviation = '\0', object defaultValue = null, CommandLineOptionValueType type = CommandLineOptionValueType.None, string description = null) + { + CommandLineOption option = new CommandLineOption(); + option.Name = name; + option.Abbreviation = abbreviation; + option.DefaultValue = defaultValue; + option.Type = type; + option.Description = description; + + Add(option); + return option; + } + + protected override void RemoveItem(int index) + { + _byName.Remove(this[index].Name); + _byAbbreviation.Remove(this[index].Abbreviation); + + base.RemoveItem(index); + } + + public T GetValueOrDefault(string name, T defaultValue = default(T)) + { + if (_byName.ContainsKey(name)) + { + return (T) _byName[name].Value; + } + return defaultValue; + } + } + + public string Name { get; set; } = null; + public char Abbreviation { get; set; } = '\0'; + + public object DefaultValue { get; set; } = null; + + /// + /// The description displayed in the help text. + /// + /// The description. + public string Description { get; set; } = null; + public object Value { get; set; } = null; + + /// + /// Gets or sets a value indicating whether this expects a value to be passed in after this option. + /// + /// true if a value is expected to be passed in after this option; otherwise, false. + public CommandLineOptionValueType Type { get; set; } = CommandLineOptionValueType.None; + } +} diff --git a/MBS.Framework/CommandLineOptionValueType.cs b/MBS.Framework/CommandLineOptionValueType.cs new file mode 100644 index 0000000..3b1470d --- /dev/null +++ b/MBS.Framework/CommandLineOptionValueType.cs @@ -0,0 +1,30 @@ +// +// CommandLineOptionValueType.cs +// +// Author: +// Mike Becker +// +// Copyright (c) 2019 Mike Becker +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +namespace MBS.Framework +{ + public enum CommandLineOptionValueType + { + None = 0, + Single = 1, + Multiple = 2 + } +} diff --git a/MBS.Framework/Context.cs b/MBS.Framework/Context.cs new file mode 100644 index 0000000..188843e --- /dev/null +++ b/MBS.Framework/Context.cs @@ -0,0 +1,95 @@ +// +// Context.cs +// +// Author: +// Mike Becker +// +// Copyright (c) 2019 Mike Becker +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +using System.Collections.Generic; + +namespace MBS.Framework +{ + public class Context + { + public class ContextCollection + : System.Collections.ObjectModel.Collection + { + protected override void ClearItems() + { + for (int i = 0; i < this.Count; i++) + { + Application.Instance.RemoveContext(this[i]); + } + base.ClearItems(); + } + protected override void InsertItem(int index, Context item) + { + base.InsertItem(index, item); + Application.Instance.AddContext(item); + } + protected override void RemoveItem(int index) + { + Application.Instance.RemoveContext(this[index]); + base.RemoveItem(index); + } + } + + public Guid ID { get; private set; } = Guid.Empty; + public string Name { get; private set; } = String.Empty; + + // public MenuBar MenuBar { get; } = new MenuBar(); + public Command.CommandCollection Commands { get; } = new Command.CommandCollection(); + + public Context(Guid id, string name) + { + ID = id; + Name = name; + } + + public override string ToString() + { + return String.Format("{0} {1}", Name, ID); + } + + private Dictionary> _CommandEventHandlers = new Dictionary>(); + public bool AttachCommandEventHandler(string commandID, EventHandler handler) + { + // handle command event handlers attached without a Command instance + if (!_CommandEventHandlers.ContainsKey(commandID)) + { + _CommandEventHandlers.Add(commandID, new List()); + } + if (!_CommandEventHandlers[commandID].Contains(handler)) + { + _CommandEventHandlers[commandID].Add(handler); + return true; + } + return false; + } + public bool ExecuteCommand(string commandID, KeyValuePair[] namedParameters = null) + { + if (_CommandEventHandlers.ContainsKey(commandID)) + { + for (int i = 0; i < _CommandEventHandlers[commandID].Count; i++) + { + _CommandEventHandlers[commandID][i](this, new CommandEventArgs(Commands[commandID], namedParameters)); + } + } + return false; + } + } +} diff --git a/MBS.Framework/ContextChangedEvent.cs b/MBS.Framework/ContextChangedEvent.cs new file mode 100644 index 0000000..766c771 --- /dev/null +++ b/MBS.Framework/ContextChangedEvent.cs @@ -0,0 +1,33 @@ +// +// ContextChangedEvent.cs +// +// Author: +// Mike Becker +// +// Copyright (c) 2019 Mike Becker +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +namespace MBS.Framework +{ + public class ContextChangedEventArgs + { + public Context Context { get; private set; } = null; + public ContextChangedEventArgs(Context ctx) + { + Context = ctx; + } + } + public delegate void ContextChangedEventHandler(object sender, ContextChangedEventArgs e); +} diff --git a/MBS.Framework/DefaultCommandLine.cs b/MBS.Framework/DefaultCommandLine.cs new file mode 100644 index 0000000..7410064 --- /dev/null +++ b/MBS.Framework/DefaultCommandLine.cs @@ -0,0 +1,27 @@ +// +// DefaultCommandLine.cs +// +// Author: +// Mike Becker +// +// Copyright (c) 2019 Mike Becker +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +namespace MBS.Framework +{ + public class DefaultCommandLine : CommandLine + { + } +} diff --git a/MBS.Framework/MBS.Framework.csproj b/MBS.Framework/MBS.Framework.csproj index 6b2e350..443afa5 100644 --- a/MBS.Framework/MBS.Framework.csproj +++ b/MBS.Framework/MBS.Framework.csproj @@ -11,7 +11,6 @@ 2.0 true ..\..\Production.snk - 4.0.2019.12 true @@ -76,6 +75,17 @@ + + + + + + + + + + + diff --git a/MBS.Framework/StockType.cs b/MBS.Framework/StockType.cs new file mode 100644 index 0000000..fe48736 --- /dev/null +++ b/MBS.Framework/StockType.cs @@ -0,0 +1,122 @@ +using System; + +namespace MBS.Framework +{ + public enum StockType + { + None, + About, + Add, + Apply, + + // these four do not have gtk-stock equivalents + ArrowDown, + ArrowLeft, + ArrowRight, + ArrowUp, + + Bold, + Cancel, + CapsLockWarning, // not for buttons + CDROM, + Clear, + Close, + ColorPicker, // not for buttons + Connect, + Convert, + Copy, + Cut, + Delete, + DialogAuthentication, // not for buttons + DialogInfo, + DialogWarning, + DialogError, + DialogQuestion, + Directory, // not for buttons + Discard, + Disconnect, + DragAndDrop, // not for buttons + DragAndDropMultiple, // not for buttons + Edit, + Execute, + File, + Find, + FindAndReplace, + Floppy, + Fullscreen, + GotoBottom, + GotoFirst, + GotoLast, + GotoTop, + GoBack, + GoDown, + GoForward, + GoUp, + HardDisk, + Help, + Home, + Index, + Indent, + Info, + Italic, + JumpTo, + JustifyCenter, + JustifyFill, + JustifyLeft, + JustifyRight, + LeaveFullscreen, + MissingImage, // not for buttons + MediaForward, + MediaNext, + MediaPause, + MediaPlay, + MediaPrevious, + MediaRecord, + MediaRewind, + MediaStop, + Network, + New, + No, + OK, + Open, + OrientationPortrait, + OrientationLandscape, + OrientationReverseLandscape, + OrientationReversePortrait, + PageSetup, + Paste, + Preferences, + Print, + PrintError, // not for buttons + PrintPaused, // not for buttons + PrintPreview, + PrintReport, // not for buttons + PrintWarning, // not for buttons + Properties, + Quit, + Redo, + Refresh, + Remove, + RevertToSaved, + Save, + SaveAs, + SelectAll, + SelectColor, + SelectFont, + SortAscending, + SortDescending, + SpellCheck, + Stop, + Strikethrough, + Undelete, + Underline, + Undo, + Unindent, + Yes, + Zoom100, + ZoomFit, + ZoomIn, + ZoomOut + } +} +