From 508aa2eac4618989d336f007b17e99057e4daa94 Mon Sep 17 00:00:00 2001 From: Daniel Lutz Date: Thu, 19 Dec 2019 08:32:40 +0100 Subject: [PATCH] init --- .gitignore | 284 ++++++++++++++++-- README.md | 12 +- src/CitaviAddOnEx.sln | 29 ++ src/CitaviAddOnEx/CitaviAddOnEx.Base.cs | 64 ++++ src/CitaviAddOnEx/CitaviAddOnEx.cs | 154 ++++++++++ src/CitaviAddOnEx/CitaviAddOnEx.csproj | 89 ++++++ src/CitaviAddOnEx/Core/Extensions.cs | 64 ++++ .../Core/FormsCollectionExtensions.cs | 80 +++++ src/CitaviAddOnEx/Core/ObservableArrayList.cs | 96 ++++++ src/CitaviAddOnEx/Forms/MacroEditorForm.cs | 55 ++++ src/CitaviAddOnEx/Properties/AssemblyInfo.cs | 36 +++ 11 files changed, 942 insertions(+), 21 deletions(-) create mode 100644 src/CitaviAddOnEx.sln create mode 100644 src/CitaviAddOnEx/CitaviAddOnEx.Base.cs create mode 100644 src/CitaviAddOnEx/CitaviAddOnEx.cs create mode 100644 src/CitaviAddOnEx/CitaviAddOnEx.csproj create mode 100644 src/CitaviAddOnEx/Core/Extensions.cs create mode 100644 src/CitaviAddOnEx/Core/FormsCollectionExtensions.cs create mode 100644 src/CitaviAddOnEx/Core/ObservableArrayList.cs create mode 100644 src/CitaviAddOnEx/Forms/MacroEditorForm.cs create mode 100644 src/CitaviAddOnEx/Properties/AssemblyInfo.cs diff --git a/.gitignore b/.gitignore index dfcfd56..9e16ee5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ + +# Created by https://www.gitignore.io/api/csharp,notepadpp,visualstudio,xamarinstudio,visualstudiocode,openframeworks+visualstudio +# Edit at https://www.gitignore.io/?templates=csharp,notepadpp,visualstudio,xamarinstudio,visualstudiocode,openframeworks+visualstudio + +### Csharp ### ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## @@ -13,9 +18,6 @@ # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs -# Mono auto generated files -mono_crash.* - # Build results [Dd]ebug/ [Dd]ebugPublic/ @@ -29,7 +31,8 @@ bld/ [Bb]in/ [Oo]bj/ [Ll]og/ -[Ll]ogs/ + +packages/ # Visual Studio 2015/2017 cache/options directory .vs/ @@ -43,10 +46,9 @@ Generated\ Files/ [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* -# NUnit +# NUNIT *.VisualState.xml TestResult.xml -nunit-*.xml # Build Results of an ATL Project [Dd]ebugPS/ @@ -127,6 +129,9 @@ _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user +# JustCode is a .NET coding add-in +.JustCode + # TeamCity is a build add-in _TeamCity* @@ -184,8 +189,6 @@ PublishScripts/ # NuGet Packages *.nupkg -# NuGet Symbol Packages -*.snupkg # The packages folder can be ignored because of Package Restore **/[Pp]ackages/* # except build/, which is used as an MSBuild target. @@ -210,14 +213,12 @@ BundleArtifacts/ Package.StoreAssociation.xml _pkginfo.txt *.appx -*.appxbundle -*.appxupload # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache -!?*.[Cc]ache/ +!*.[Cc]ache/ # Others ClientBin/ @@ -237,6 +238,8 @@ orleans.codegen.cs # Since there are multiple workflows, uncomment next line to ignore bower_components # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) #bower_components/ +# ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true +**/wwwroot/lib/ # RIA/Silverlight projects Generated_Code/ @@ -261,9 +264,6 @@ ServiceFabricBackup/ *.bim.layout *.bim_*.settings *.rptproj.rsuser -*- [Bb]ackup.rdl -*- [Bb]ackup ([0-9]).rdl -*- [Bb]ackup ([0-9][0-9]).rdl # Microsoft Fakes FakesAssemblies/ @@ -299,6 +299,10 @@ paket-files/ # FAKE - F# Make .fake/ +# JetBrains Rider +.idea/ +*.sln.iml + # CodeRush personal settings .cr/personal @@ -340,11 +344,251 @@ ASALocalRun/ # Local History for Visual Studio .localhistory/ -# BeatPulse healthcheck temp database -healthchecksdb +### NotepadPP ### +# Notepad++ backups # +*.bak + +### OpenFrameworks+VisualStudio ### +# ignore generated binaries +# but not the data folder + +/bin/* +!/bin/data/ + +# general + +[Bb]uild/ +*.o +[Dd]ebug*/ +[Rr]elease*/ +*.mode* +*.app/ +.svn/ + +# IDE files which should +# be ignored + +# XCode +*.pbxuser +*.perspective +*.perspectivev3 +*.mode1v3 +*.mode2v3 +# XCode 4 +xcuserdata +*.xcworkspace + +# Code::Blocks +*.depend +*.layout + +# Visual Studio + +# Eclipse +.metadata +local.properties +.externalToolBuilders + +# operating system + +# Linux +# KDE +.directory +.AppleDouble + +# OSX +.DS_Store +*.swp +*~.nib +# Thumbnails +._* + +# Windows +# Image file caches +Thumbs.db +# Folder config file +Desktop.ini + +# Android +.csettings + +### OpenFrameworks+VisualStudio Patch ### + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history + +### XamarinStudio ### +bin/ +obj/ +.packages + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files + +# User-specific files (MonoDevelop/Xamarin Studio) + +# Build results + +# Visual Studio 2015/2017 cache/options directory +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files + +# MSTest test Results + +# NUNIT + +# Build Results of an ATL Project + +# Benchmark Results + +# .NET Core + +# StyleCop + +# Files built by Visual Studio + +# Chutzpah Test files + +# Visual C++ cache files + +# Visual Studio profiler + +# Visual Studio Trace Files + +# TFS 2012 Local Workspace + +# Guidance Automation Toolkit + +# ReSharper is a .NET coding add-in + +# JustCode is a .NET coding add-in + +# TeamCity is a build add-in + +# DotCover is a Code Coverage Tool + +# AxoCover is a Code Coverage Tool + +# Visual Studio code coverage results + +# NCrunch -# Backup folder for Package Reference Convert tool in Visual Studio 2017 -MigrationBackup/ +# MightyMoose + +# Web workbench (sass) + +# Installshield output folder + +# DocProject is a documentation generator add-in + +# Click-Once directory + +# Publish Web Output +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted + +# NuGet Packages +# The packages folder can be ignored because of Package Restore +# except build/, which is used as an MSBuild target. +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files + +# Microsoft Azure Build Output + +# Microsoft Azure Emulator + +# Windows Store app package directories and files + +# Visual Studio cache files +# files ending in .cache can be ignored +# but keep track of directories ending in .cache + +# Others + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ +# ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true + +# RIA/Silverlight projects + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) + +# SQL Server files + +# Business Intelligence projects + +# Microsoft Fakes + +# GhostDoc plugin setting file + +# Node.js Tools for Visual Studio + +# Visual Studio 6 build log + +# Visual Studio 6 workspace options file + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) + +# Visual Studio LightSwitch build output + +# Paket dependency manager + +# FAKE - F# Make + +# JetBrains Rider + +# CodeRush personal settings + +# Python Tools for Visual Studio (PTVS) + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio + +# Telerik's JustMock configuration file + +# BizTalk build output + +# OpenCover UI analysis results + +# Azure Stream Analytics local run output + +# MSBuild Binary and Structured Log + +# NVidia Nsight GPU debugger configuration file + +# MFractors (Xamarin productivity tool) working folder + +# Local History for Visual Studio -# Ionide (cross platform F# VS Code tools) working folder -.ionide/ +# End of https://www.gitignore.io/api/csharp,notepadpp,visualstudio,xamarinstudio,visualstudiocode,openframeworks+visualstudio +# End of https://www.gitignore.io/api/csharp,notepadpp,visualstudio,xamarinstudio,visualstudiocode,openframeworks+visualstudio \ No newline at end of file diff --git a/README.md b/README.md index afaac95..98188b6 100644 --- a/README.md +++ b/README.md @@ -1 +1,11 @@ -# CitaviAddOnEx \ No newline at end of file +# CitaviAddOnEx + +This repository contains a class library that extends the addon programming model of Swiss Academic Citavi to support all dialogs inherited from the `FormBase` class. + +## Disclaimer + +>There are no support claims by the company **Swiss Academic Software GmbH**, the provider of **Citavi** or other liability claims for problems or data loss. Any use is at your own risk. All rights to the name **Citavi** and any logos used are owned by **Swiss Academic Software GmbH**. + +## License + +This project is licensed under the [MIT](LICENSE) License diff --git a/src/CitaviAddOnEx.sln b/src/CitaviAddOnEx.sln new file mode 100644 index 0000000..e60a7a1 --- /dev/null +++ b/src/CitaviAddOnEx.sln @@ -0,0 +1,29 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29509.3 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CitaviAddOnEx", "CitaviAddOnEx\CitaviAddOnEx.csproj", "{05227BDE-6BFE-4520-B4BF-B15D2BA0CC45}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {05227BDE-6BFE-4520-B4BF-B15D2BA0CC45}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {05227BDE-6BFE-4520-B4BF-B15D2BA0CC45}.Debug|Any CPU.Build.0 = Debug|Any CPU + {05227BDE-6BFE-4520-B4BF-B15D2BA0CC45}.Release|Any CPU.ActiveCfg = Release|Any CPU + {05227BDE-6BFE-4520-B4BF-B15D2BA0CC45}.Release|Any CPU.Build.0 = Release|Any CPU + {8ED82589-B7D8-49AF-9FAC-511E62CC9355}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8ED82589-B7D8-49AF-9FAC-511E62CC9355}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8ED82589-B7D8-49AF-9FAC-511E62CC9355}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8ED82589-B7D8-49AF-9FAC-511E62CC9355}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {AB7AB14E-8A07-4B35-9CA6-D9B8F3B37D32} + EndGlobalSection +EndGlobal diff --git a/src/CitaviAddOnEx/CitaviAddOnEx.Base.cs b/src/CitaviAddOnEx/CitaviAddOnEx.Base.cs new file mode 100644 index 0000000..bd1385f --- /dev/null +++ b/src/CitaviAddOnEx/CitaviAddOnEx.Base.cs @@ -0,0 +1,64 @@ +using SwissAcademic.Controls; +using SwissAcademic.Drawing; +using System; +using System.Windows.Forms; + +namespace SwissAcademic.Citavi.Shell +{ + public abstract partial class CitaviAddOnEx + { + #region Properties + + public sealed override AddOnHostingForm HostingForm => Enum.TryParse(typeof(T).Name, true, out AddOnHostingForm addOnHostingForm) + ? addOnHostingForm + : AddOnHostingForm.None; + + #endregion + + #region Methods + + sealed protected override void OnApplicationIdle(Form form) + { + if (form is T t) OnApplicationIdle(t); + base.OnApplicationIdle(form); + } + + sealed protected override void OnBeforePerformingCommand(BeforePerformingCommandEventArgs args) + { + if (args.Form is T t) OnBeforePerformingCommand(t, args); + base.OnBeforePerformingCommand(args); + + } + + sealed protected override void OnChangingColorScheme(Form form, ColorScheme colorScheme) + { + if (form is T t) OnChangingColorScheme(t, colorScheme); + base.OnChangingColorScheme(form, colorScheme); + } + + sealed protected override void OnHostingFormLoaded(Form form) + { + if (form is T t) + { + OnHostingFormLoaded(t); + form.FormClosed += Form_FormClosed; + } + base.OnHostingFormLoaded(form); + } + + sealed protected override void OnLocalizing(Form form) + { + if (form is T t) OnLocalizing(t); + base.OnLocalizing(form); + } + + void Form_FormClosed(object sender, FormClosedEventArgs e) + { + if (sender is Form form) form.FormClosed -= Form_FormClosed; + + if (sender is T t) OnHostingFormClosed(t); + } + + #endregion + } +} diff --git a/src/CitaviAddOnEx/CitaviAddOnEx.cs b/src/CitaviAddOnEx/CitaviAddOnEx.cs new file mode 100644 index 0000000..50f9bb9 --- /dev/null +++ b/src/CitaviAddOnEx/CitaviAddOnEx.cs @@ -0,0 +1,154 @@ +using Infragistics.Win.UltraWinToolbars; +using SwissAcademic.Controls; +using SwissAcademic.Drawing; +using System; +using System.Linq; +using System.Windows.Forms; + +namespace SwissAcademic.Citavi.Shell +{ + public abstract partial class CitaviAddOnEx : CitaviAddOn where T : FormBase + { + #region Constructors + + public CitaviAddOnEx() => ObserveApplication(true); + + #endregion + + #region EventHandler + + void Application_Idle(object sender, EventArgs e) => Application.OpenForms.OfType().ForEach(form => OnApplicationIdle(form)); + + void Application_Exit(object sender, EventArgs e) => ObserveApplication(false); + + void Engine_SettingsChanged(object sender, SettingsEventArgs e) + { + if (e.Name.Equals(nameof(Program.Engine.Settings.General.UICulture), StringComparison.OrdinalIgnoreCase)) + { + Application.OpenForms.OfType().ForEach(form => OnLocalizing(form)); + } + } + + void Project_SettingsChanged(object sender, ProjectSettingsEventArgs e) + { + if (e?.ProjectSettingsType == ProjectSettingsType.ColorScheme && sender is Project project) + { + Application.OpenForms.OfType().Where(form => form.Project == project).ForEach(form => OnChangingColorScheme(form, form.Project.ProjectSettings.ColorScheme)); + } + } + + void Forms_Added(object sender, ListChangedEventArgs args) + { + foreach (var form in args.Forms) + { + if (form is T t) + { + OnHostingFormLoaded(t); + ChangedToolClickHandler(t); + if (t is ProjectShellForm shellForm) ObserveProject(shellForm, true); + } + } + } + + void Forms_Removed(object sender, ListChangedEventArgs args) + { + foreach (var form in args.Forms) + { + if (form is T t) + { + OnHostingFormClosed(t); + if (t is ProjectShellForm shellForm) ObserveProject(shellForm, false); + } + } + } + + #endregion + + #region Methods + + void ObserveApplication(bool start) + { + if (IsUnSupportedAddonHostingForm) + { + + if (start) + { + Application.OpenForms.AddListChangedEventHandler(Forms_Added, ListChangedType.Added); + Application.OpenForms.AddListChangedEventHandler(Forms_Removed, ListChangedType.Removed); + Application.Idle += Application_Idle; + Application.ApplicationExit += Application_Exit; + Program.Engine.SettingsChanged += Engine_SettingsChanged; + } + else + { + Application.OpenForms.RemoveListChangedEventHandler(Forms_Added, ListChangedType.Added); + Application.OpenForms.RemoveListChangedEventHandler(Forms_Removed, ListChangedType.Removed); + Application.Idle -= Application_Idle; + Application.ApplicationExit -= Application_Exit; + Program.Engine.SettingsChanged -= Engine_SettingsChanged; + } + } + } + + void ObserveProject(ProjectShellForm shellForm, bool start) + { + try + { + if (shellForm.Project == null || shellForm.Project.IsDisposed) return; + + if (start) + { + shellForm.Project.SettingsChanged += Project_SettingsChanged; + } + else + { + shellForm.Project.SettingsChanged -= Project_SettingsChanged; + } + } + catch (Exception) + { + + } + } + + void ChangedToolClickHandler(T form) + { + var toolbarsManager = form.GetToolbarsManager(); + var registredDelegates = toolbarsManager?.RemoveEventHandlersFromEvent("ToolClick"); + ToolClickEventHandler clickEventHandler = (sender, args) => + { + var e = new BeforePerformingCommandEventArgs(form, args.Tool.Key, args.ListToolItem?.Key, null); + OnBeforePerformingCommand(form, e); + if (!e.Handled) + { + foreach (var del in registredDelegates) + { + del.DynamicInvoke(sender, args); + } + } + }; + + toolbarsManager?.AddEventHandlerForEvent("ToolClick", clickEventHandler); + } + + public virtual void OnApplicationIdle(T form) { } + + public virtual void OnBeforePerformingCommand(T form, BeforePerformingCommandEventArgs e) { } + + public virtual void OnChangingColorScheme(T form, ColorScheme colorScheme) { } + + public virtual void OnHostingFormLoaded(T form) { } + + public virtual void OnHostingFormClosed(T form) { } + + public virtual void OnLocalizing(T form) { } + + #endregion + + #region Properties + + public bool IsUnSupportedAddonHostingForm => HostingForm == AddOnHostingForm.None; + + #endregion + } +} diff --git a/src/CitaviAddOnEx/CitaviAddOnEx.csproj b/src/CitaviAddOnEx/CitaviAddOnEx.csproj new file mode 100644 index 0000000..708d1e5 --- /dev/null +++ b/src/CitaviAddOnEx/CitaviAddOnEx.csproj @@ -0,0 +1,89 @@ + + + + + Debug + AnyCPU + {05227BDE-6BFE-4520-B4BF-B15D2BA0CC45} + Library + Properties + SwissAcademic.Citavi.Shell + CitaviAddOnEx + v4.6.1 + 512 + true + + + true + pdbonly + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + none + true + bin\Release\ + + + prompt + 4 + + + + ..\..\..\..\..\Program Files (x86)\Citavi 6\bin\Citavi.exe + False + + + False + ..\..\..\..\Program Files (x86)\Citavi 6\bin\Infragistics4.Shared.v11.2.dll + False + + + False + ..\..\..\..\Program Files (x86)\Citavi 6\bin\Infragistics4.Win.UltraWinToolbars.v11.2.dll + False + + + False + ..\..\..\..\Program Files (x86)\Citavi 6\bin\Infragistics4.Win.v11.2.dll + False + + + ..\..\..\..\..\Program Files (x86)\Citavi 6\bin\SwissAcademic.dll + False + + + ..\..\..\..\..\Program Files (x86)\Citavi 6\bin\SwissAcademic.Citavi.dll + False + + + ..\..\..\..\..\Program Files (x86)\Citavi 6\bin\SwissAcademic.Controls.dll + False + + + + + + + + + + + + + + CitaviAddOnEx.cs + + + + + + + + + + + \ No newline at end of file diff --git a/src/CitaviAddOnEx/Core/Extensions.cs b/src/CitaviAddOnEx/Core/Extensions.cs new file mode 100644 index 0000000..6f14170 --- /dev/null +++ b/src/CitaviAddOnEx/Core/Extensions.cs @@ -0,0 +1,64 @@ +using SwissAcademic.Controls; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace SwissAcademic.Citavi.Shell +{ + internal static class Extensions + { + #region Fields + + static readonly BindingFlags fieldBindingFlags = BindingFlags.Instance | BindingFlags.NonPublic; + static readonly BindingFlags staticEventBindingFlags = fieldBindingFlags | BindingFlags.Static; + static readonly BindingFlags staticFieldBindingFlags = BindingFlags.NonPublic | BindingFlags.Static; + + #endregion + + #region Methods + + public static ToolbarsManager GetToolbarsManager(this T form) where T : FormBase => form.GetType().GetField("toolbarsManager", fieldBindingFlags)?.GetValue(form) as ToolbarsManager; + + public static IReadOnlyList RemoveEventHandlersFromEvent(this ToolbarsManager toolbarsManager, string eventName) + { + + var eventsPropertyInfo = toolbarsManager + .GetType() + .GetProperties(staticEventBindingFlags) + .Where(p => p.Name.Equals("Events", StringComparison.OrdinalIgnoreCase) && p.PropertyType.Equals(typeof(Infragistics.Shared.EventHandlerDictionary))) + .FirstOrDefault(); + + var eventHandlerList = eventsPropertyInfo? + .GetValue(toolbarsManager, new object[] { }) as Infragistics.Shared.EventHandlerDictionary; + + var eventFieldInfo = typeof(ToolbarsManager) + .BaseType + .GetFields(staticFieldBindingFlags) + .FirstOrDefault(fi => fi.Name.Equals("Event_" + eventName, StringComparison.OrdinalIgnoreCase)); + + var eventKey = eventFieldInfo.GetValue(toolbarsManager); + + var currentEventHandler = eventHandlerList[eventKey] as Delegate; + Delegate[] currentRegistredHandlers = currentEventHandler.GetInvocationList(); + foreach (var item in currentRegistredHandlers) + { + toolbarsManager.GetType().GetEvent(eventName).RemoveEventHandler(toolbarsManager, item); + } + + return currentRegistredHandlers.ToList().AsReadOnly(); + } + + public static void AddEventHandlerForEvent(this ToolbarsManager toolbarsManager, string eventName, Delegate @delegate) => toolbarsManager.GetType().GetEvent(eventName).AddEventHandler(toolbarsManager, @delegate); + + public static void ForEach(this IEnumerable iEnumerable, Action action) + { + foreach (var item in iEnumerable) + { + action.Invoke(item); + } + } + + #endregion + } +} diff --git a/src/CitaviAddOnEx/Core/FormsCollectionExtensions.cs b/src/CitaviAddOnEx/Core/FormsCollectionExtensions.cs new file mode 100644 index 0000000..b796d44 --- /dev/null +++ b/src/CitaviAddOnEx/Core/FormsCollectionExtensions.cs @@ -0,0 +1,80 @@ +using System.Collections; +using System.Reflection; +using System.Windows.Forms; + +namespace SwissAcademic.Citavi.Shell +{ + internal static class FormsCollectionExtensions + { + #region Fields + + static readonly BindingFlags fieldBindingFlags = BindingFlags.Instance | BindingFlags.NonPublic; + + #endregion + + #region Methods + + public static void AddListChangedEventHandler(this FormCollection collection, ListChangedEventHandler eventHandler, ListChangedType changedType) + { + var innerListlistFieldInfo = collection.GetType().BaseType.GetField("list", fieldBindingFlags); + var innerlist = innerListlistFieldInfo?.GetValue(Application.OpenForms); + + if (!(innerlist is ObservableArrayList)) + { + var newInnerList = new ObservableArrayList(); + + foreach (var item in (innerlist as ArrayList)) + { + newInnerList.Add(item); + } + + innerListlistFieldInfo.SetValue(Application.OpenForms, newInnerList); + } + + if (innerListlistFieldInfo?.GetValue(Application.OpenForms) is ObservableArrayList currentInnerList) + { + switch (changedType) + { + case ListChangedType.Added: + currentInnerList.Added += eventHandler; + break; + case ListChangedType.Removed: + currentInnerList.Removed += eventHandler; + break; + } + } + } + + public static void RemoveListChangedEventHandler(this FormCollection collection, ListChangedEventHandler eventHandler, ListChangedType changedType) + { + var innerListlistFieldInfo = collection.GetType().BaseType.GetField("list", fieldBindingFlags); + var innerlist = innerListlistFieldInfo?.GetValue(Application.OpenForms); + + if (!(innerlist is ObservableArrayList)) + { + var newInnerList = new ObservableArrayList(); + foreach (var item in (innerlist as ArrayList)) + { + newInnerList.Add(item); + } + + innerListlistFieldInfo.SetValue(Application.OpenForms, newInnerList); + } + + if (innerListlistFieldInfo?.GetValue(Application.OpenForms) is ObservableArrayList currentInnerList) + { + switch (changedType) + { + case ListChangedType.Added: + currentInnerList.Added -= eventHandler; + break; + case ListChangedType.Removed: + currentInnerList.Removed -= eventHandler; + break; + } + } + } + + #endregion + } +} diff --git a/src/CitaviAddOnEx/Core/ObservableArrayList.cs b/src/CitaviAddOnEx/Core/ObservableArrayList.cs new file mode 100644 index 0000000..231d270 --- /dev/null +++ b/src/CitaviAddOnEx/Core/ObservableArrayList.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections; + +namespace SwissAcademic.Citavi.Shell +{ + internal delegate void ListChangedEventHandler(object sender, ListChangedEventArgs args); + + internal class ObservableArrayList : ArrayList + { + #region Events + + public event ListChangedEventHandler Added; + + public event ListChangedEventHandler Removed; + + protected void OnAdded(ListChangedEventArgs args) + { + Added?.Invoke(this, args); + } + + protected void OnRemoved(ListChangedEventArgs args) + { + Removed?.Invoke(this, args); + } + + #endregion + + #region Methods + + public override int Add(object value) + { + var result = base.Add(value); + OnAdded(new ListChangedEventArgs(ListChangedType.Added, value)); + return result; + } + + public override void AddRange(ICollection objects) + { + base.AddRange(objects); + OnAdded(new ListChangedEventArgs(ListChangedType.Added, objects)); ; + } + + public override void Remove(object value) + { + base.Remove(value); + OnRemoved(new ListChangedEventArgs(ListChangedType.Removed, value)); + } + + public override void RemoveRange(int index, int count) + { + var objects = GetRange(index, count); + base.RemoveRange(index, count); + OnRemoved(new ListChangedEventArgs(ListChangedType.Removed, objects)); + } + + #endregion + } + + internal class ListChangedEventArgs : EventArgs + { + #region Constructors + + private ListChangedEventArgs() + { + ChangedType = ListChangedType.Unknown; + Forms = null; + } + + public ListChangedEventArgs(ListChangedType changedType, params object[] items) + { + ChangedType = changedType; + Forms = items; + } + + #endregion + + #region Properties + + public new ListChangedEventArgs Empty => new ListChangedEventArgs(); + + public ListChangedType ChangedType { get; } + + public object[] Forms { get; } + + #endregion + + } + + public enum ListChangedType + { + Added, + Removed, + Unknown + } + +} diff --git a/src/CitaviAddOnEx/Forms/MacroEditorForm.cs b/src/CitaviAddOnEx/Forms/MacroEditorForm.cs new file mode 100644 index 0000000..fd1f4cb --- /dev/null +++ b/src/CitaviAddOnEx/Forms/MacroEditorForm.cs @@ -0,0 +1,55 @@ +using Infragistics.Win.UltraWinToolbars; +using SwissAcademic.Controls; + +namespace SwissAcademic.Citavi.Shell +{ + public static class MacroEditorFormExtensions + { + public static MacroEditorFormCommandbar GetCommandbar(this MacroEditorForm macroEditorForm) + { + return new MacroEditorFormCommandbar(macroEditorForm.GetToolbarsManager().Toolbars["menu"]); + } + } + + public class MacroEditorFormCommandbar : Commandbar + { + #region Constructors + + internal MacroEditorFormCommandbar(UltraToolbar ultraToolbar) : base(ultraToolbar) { } + + #endregion + + #region Methods + + public CommandbarMenu GetCommandbarMenu(MacroEditorFormCommandbarMenuId macroEditorFormCommandbarMenuId) + { + switch (macroEditorFormCommandbarMenuId) + { + case MacroEditorFormCommandbarMenuId.File: + return CommandbarMenu.Create(this.Toolbar.Tools["FileMenu"] as PopupMenuTool); + case MacroEditorFormCommandbarMenuId.Edit: + return CommandbarMenu.Create(this.Toolbar.Tools["EditMenu"] as PopupMenuTool); + case MacroEditorFormCommandbarMenuId.Build: + return CommandbarMenu.Create(this.Toolbar.Tools["BuildMenu"] as PopupMenuTool); + case MacroEditorFormCommandbarMenuId.Tools: + return CommandbarMenu.Create(this.Toolbar.Tools["ToolsMenu"] as PopupMenuTool); + case MacroEditorFormCommandbarMenuId.Help: + return CommandbarMenu.Create(this.Toolbar.Tools["HelpMenu"] as PopupMenuTool); + default: + return null; + } + } + + #endregion + } + + public enum MacroEditorFormCommandbarMenuId + { + File, + Edit, + Build, + Tools, + Help + } + +} diff --git a/src/CitaviAddOnEx/Properties/AssemblyInfo.cs b/src/CitaviAddOnEx/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..43b24be --- /dev/null +++ b/src/CitaviAddOnEx/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 einer Assembly zugeordnet sind. +[assembly: AssemblyTitle("CitaviAddOnEx")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CitaviAddOnEx")] +[assembly: AssemblyCopyright("Copyright © 2019 Daniel Lutz")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly +// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von +// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen. +[assembly: ComVisible(false)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("05227bde-6bfe-4520-b4bf-b15d2ba0cc45")] + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden, +// indem Sie "*" wie unten gezeigt eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")]