diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..49ffb1fb --- /dev/null +++ b/.gitignore @@ -0,0 +1,34 @@ +Thumbs.db +*.obj +*.exe +*.pdb +*.user +*.aps +*.pch +*.vspscc +*_i.c +*_p.c +*.ncb +*.suo +*.sln.docstates +*.tlb +*.tlh +*.bak +*.cache +*.ilk +*.log +[Bb]in +[Dd]ebug*/ +*.lib +*.sbr +obj/ +[Rr]elease*/ +_ReSharper*/ +[Tt]est[Rr]esult* +*.vssscc +$tf*/ +.tfignore +*.psess +*.vspx +*.vspx +*.StyleCop diff --git a/ConfigBatchConverter/ConfigBatchConverter.csproj b/ConfigBatchConverter/ConfigBatchConverter.csproj new file mode 100644 index 00000000..78baad39 --- /dev/null +++ b/ConfigBatchConverter/ConfigBatchConverter.csproj @@ -0,0 +1,65 @@ + + + + + Debug + AnyCPU + {786B5A56-1721-403F-B83F-6D890DBA0324} + Exe + Properties + ConfigBatchConverter + ConfigBatchConverter + v4.0 + 512 + Client + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + {eb60ffbc-51f9-42f7-b22b-2200c3f0cb64} + StagWare.FanControl.Configurations + + + + + + + + \ No newline at end of file diff --git a/ConfigBatchConverter/Program.cs b/ConfigBatchConverter/Program.cs new file mode 100644 index 00000000..f9d5ad81 --- /dev/null +++ b/ConfigBatchConverter/Program.cs @@ -0,0 +1,57 @@ +using StagWare.FanControl.Configurations; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Xml.Serialization; + +namespace ConfigBatchConverter +{ + public class Program + { + private static XmlSerializer serializer = new XmlSerializer(typeof(FanControlConfig)); + + public static void Main(string[] args) + { + string src = @"D:\Users\Stefan\Skydrive\Öffentlich\NBFC\Configs (V1)"; + string dst = @"C:\Program Files\NBFC Service\Configs"; + + var dstManager = new FanControlConfigManager(dst); + + foreach (string s in Directory.GetFiles(src, "*.config")) + { + FanControlConfig cfg = null; + + if (TryLoadFanControlConfigV1(s, out cfg)) + { + try + { + dstManager.AddConfig(new FanControlConfigV2(cfg), cfg.UniqueId); + } + catch + { + } + } + } + } + + private static bool TryLoadFanControlConfigV1(string configFilePath, out FanControlConfig config) + { + using (FileStream fs = new FileStream(configFilePath, FileMode.Open)) + { + try + { + config = (FanControlConfig)serializer.Deserialize(fs); + } + catch + { + config = null; + return false; + } + } + + return config != null; + } + } +} diff --git a/ConfigBatchConverter/Properties/AssemblyInfo.cs b/ConfigBatchConverter/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..3f268970 --- /dev/null +++ b/ConfigBatchConverter/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ConfigBatchConverter")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Stefan Hirschmann - StagWare")] +[assembly: AssemblyProduct("ConfigBatchConverter")] +[assembly: AssemblyCopyright("Copyright © 2013 Stefan Hirschmann")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("1ce29d0a-7ac4-4d53-8fe8-6a06bac94dfa")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/ConfigBatchConverter/app.config b/ConfigBatchConverter/app.config new file mode 100644 index 00000000..2f7cce78 --- /dev/null +++ b/ConfigBatchConverter/app.config @@ -0,0 +1,3 @@ + + + diff --git a/ConfigEditor/App.xaml b/ConfigEditor/App.xaml new file mode 100644 index 00000000..506fa9b7 --- /dev/null +++ b/ConfigEditor/App.xaml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ConfigEditor/App.xaml.cs b/ConfigEditor/App.xaml.cs new file mode 100644 index 00000000..3ff98d6b --- /dev/null +++ b/ConfigEditor/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Windows; +using ConfigEditor.ValueConverters; + +namespace ConfigEditor +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/ConfigEditor/Behaviors/SelectionChangedBehavior.cs b/ConfigEditor/Behaviors/SelectionChangedBehavior.cs new file mode 100644 index 00000000..f4abc120 --- /dev/null +++ b/ConfigEditor/Behaviors/SelectionChangedBehavior.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows.Input; +using System.Windows.Controls.Primitives; +using System.Windows.Controls; +using System.Windows; + +namespace ConfigEditor.Behaviors +{ + public class SelectionChangedBehaviour + { + public static readonly DependencyProperty CommandProperty = + DependencyProperty.RegisterAttached( + "Command", + typeof(ICommand), + typeof(SelectionChangedBehaviour), + new PropertyMetadata(PropertyChangedCallback)); + + public static void PropertyChangedCallback(DependencyObject depObj, DependencyPropertyChangedEventArgs args) + { + Selector selector = (Selector)depObj; + + if (selector != null) + { + selector.SelectionChanged += new SelectionChangedEventHandler(SelectionChanged); + } + } + + public static ICommand GetCommand(UIElement element) + { + return (ICommand)element.GetValue(CommandProperty); + } + + public static void SetCommand(UIElement element, ICommand command) + { + element.SetValue(CommandProperty, command); + } + + private static void SelectionChanged(object sender, SelectionChangedEventArgs e) + { + Selector selector = (Selector)sender; + + if (selector != null) + { + ICommand command = selector.GetValue(CommandProperty) as ICommand; + + if (command != null) + { + command.Execute(selector.SelectedItem); + } + } + } + } +} diff --git a/ConfigEditor/Commands/RelayCommand.cs b/ConfigEditor/Commands/RelayCommand.cs new file mode 100644 index 00000000..9b505719 --- /dev/null +++ b/ConfigEditor/Commands/RelayCommand.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows.Input; + +namespace ConfigEditor.Commands +{ + public class RelayCommand : ICommand + { + #region Events + + public event EventHandler CanExecuteChanged; + + #endregion + + #region Fields + + private readonly Action execute; + private readonly Predicate canExecute; + + #endregion + + #region Constructors + + public RelayCommand(Action execute) + : this(execute, null) + { + } + + public RelayCommand(Action execute, Predicate canExecute) + { + this.execute = execute; + this.canExecute = canExecute; + } + + #endregion + + #region ICommand Members + + public bool CanExecute(object parameter) + { + return canExecute == null ? true : canExecute(parameter); + } + + public void RaiseCanExecuteChanged() + { + if (CanExecuteChanged != null) + { + CanExecuteChanged(this, EventArgs.Empty); + } + } + + public void Execute(object parameter) + { + execute(parameter); + } + + #endregion + } +} diff --git a/ConfigEditor/ConfigEditor.csproj b/ConfigEditor/ConfigEditor.csproj new file mode 100644 index 00000000..59ec40cf --- /dev/null +++ b/ConfigEditor/ConfigEditor.csproj @@ -0,0 +1,184 @@ + + + + + Debug + AnyCPU + {A2E2E628-7BDA-4072-83DE-B28DE7EA85A9} + WinExe + Properties + ConfigEditor + ConfigEditor + v4.0 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + ConfigEditor.App + + + nbfc.ico + + + + ..\packages\Ookii.Dialogs.1.0\lib\net35\Ookii.Dialogs.Wpf.dll + False + + + + + + + + + + + 4.0 + + + + + + ..\packages\Extended.Wpf.Toolkit.2.0.0\lib\net40\Xceed.Wpf.Toolkit.dll + + + + + MSBuild:Compile + Designer + + + + + + + + + + + + + + + + + + + + + + + FanSpeedOverrideWindow.xaml + + + + RegisterWriteConfigWindow.xaml + + + RequestConfigNameWindow.xaml + + + TemperatureThresholdWindow.xaml + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + FanConfigWindow.xaml + + + MainWindow.xaml + Code + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + {eb60ffbc-51f9-42f7-b22b-2200c3f0cb64} + StagWare.FanControl.Configurations + + + + + + + + \ No newline at end of file diff --git a/ConfigEditor/ExtensionMethods/CollectionExtensionMethods.cs b/ConfigEditor/ExtensionMethods/CollectionExtensionMethods.cs new file mode 100644 index 00000000..0ae50b6f --- /dev/null +++ b/ConfigEditor/ExtensionMethods/CollectionExtensionMethods.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; + +namespace ConfigEditor +{ + public static class CollectionExtensionMethods + { + public static int Replace(this Collection oc, TSource oldItem, TSource newItem) + { + int idx = oc.IndexOf(oldItem); + + if (idx >= 0) + { + oc[idx] = newItem; + return idx; + } + else + { + throw new InvalidOperationException("The collection does not contain oldItem"); + } + } + } +} diff --git a/ConfigEditor/ExtensionMethods/IconExtensionMethods.cs b/ConfigEditor/ExtensionMethods/IconExtensionMethods.cs new file mode 100644 index 00000000..0d709795 --- /dev/null +++ b/ConfigEditor/ExtensionMethods/IconExtensionMethods.cs @@ -0,0 +1,21 @@ +using System.Drawing; +using System.Windows; +using System.Windows.Interop; +using System.Windows.Media; +using System.Windows.Media.Imaging; + +namespace ConfigEditor +{ + public static class IconExtensionMethods + { + public static ImageSource ToImageSource(this Icon icon) + { + ImageSource imageSource = Imaging.CreateBitmapSourceFromHIcon( + icon.Handle, + Int32Rect.Empty, + BitmapSizeOptions.FromEmptyOptions()); + + return imageSource; + } + } +} diff --git a/ConfigEditor/ExtensionMethods/MouseDeviceExtensionMethods.cs b/ConfigEditor/ExtensionMethods/MouseDeviceExtensionMethods.cs new file mode 100644 index 00000000..2068ad34 --- /dev/null +++ b/ConfigEditor/ExtensionMethods/MouseDeviceExtensionMethods.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Input; + +namespace ConfigEditor +{ + public static class MouseDeviceExtensionMethods + { + public static bool IsMouseOverElement(this MouseDevice device, Type elementType) + { + var element = device.DirectlyOver as FrameworkElement; + + return element != null + && element.Parent != null + && element.Parent.GetType().IsAssignableFrom(elementType); + } + } +} diff --git a/ConfigEditor/Properties/AssemblyInfo.cs b/ConfigEditor/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..4df83a52 --- /dev/null +++ b/ConfigEditor/Properties/AssemblyInfo.cs @@ -0,0 +1,54 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ConfigEditor")] +[assembly: AssemblyDescription("Config Editor for NoteBook FanControl")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Stefan Hirschmann - StagWare")] +[assembly: AssemblyProduct("ConfigEditor")] +[assembly: AssemblyCopyright("Copyright © 2013 Stefan Hirschmann")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// In order to begin building localizable applications, set +// CultureYouAreCodingWith in your .csproj file +// inside a . For example, if you are using US english +// in your source files, set the to en-US. Then uncomment +// the NeutralResourceLanguage attribute below. Update the "en-US" in +// the line below to match the UICulture setting in the project file. + +// [assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + // (used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + // (used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: NeutralResourcesLanguageAttribute("en")] diff --git a/ConfigEditor/Properties/Resources.Designer.cs b/ConfigEditor/Properties/Resources.Designer.cs new file mode 100644 index 00000000..f21507bc --- /dev/null +++ b/ConfigEditor/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.18051 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace ConfigEditor.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ConfigEditor.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/ConfigEditor/Properties/Resources.resx b/ConfigEditor/Properties/Resources.resx new file mode 100644 index 00000000..af7dbebb --- /dev/null +++ b/ConfigEditor/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/ConfigEditor/Properties/Settings.Designer.cs b/ConfigEditor/Properties/Settings.Designer.cs new file mode 100644 index 00000000..ec11b013 --- /dev/null +++ b/ConfigEditor/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.18051 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace ConfigEditor.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/ConfigEditor/Properties/Settings.settings b/ConfigEditor/Properties/Settings.settings new file mode 100644 index 00000000..033d7a5e --- /dev/null +++ b/ConfigEditor/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/ConfigEditor/ValueConverters/BooleanToBrushConverter.cs b/ConfigEditor/ValueConverters/BooleanToBrushConverter.cs new file mode 100644 index 00000000..afbe2881 --- /dev/null +++ b/ConfigEditor/ValueConverters/BooleanToBrushConverter.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Data; +using System.Windows.Media; + +namespace ConfigEditor.ValueConverters +{ + [ValueConversion(typeof(bool), typeof(Brush))] + public class BooleanToBrushConverter : IMultiValueConverter + { + public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + if (!(bool)values[1]) + { + return Brushes.Tomato; + } + else if (!(bool)values[0]) + { + return Brushes.Gold; + } + else + { + return SystemColors.ControlLightLightBrush; + } + } + + public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/ConfigEditor/ValueConverters/BooleanToButtonTextConverter.cs b/ConfigEditor/ValueConverters/BooleanToButtonTextConverter.cs new file mode 100644 index 00000000..0f178770 --- /dev/null +++ b/ConfigEditor/ValueConverters/BooleanToButtonTextConverter.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows.Data; + +namespace ConfigEditor.ValueConverters +{ + [ValueConversion(typeof(bool), typeof(string))] + public class BooleanToButtonTextConverter : IValueConverter + { + #region Constants + + private const string ButtonTextOK = "OK"; + private const string ButtonTextOverwrite = "Overwrite"; + + #endregion + + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + return (bool)value ? ButtonTextOK : ButtonTextOverwrite; + } + + public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/ConfigEditor/ValueConverters/InvertBooleanConverter.cs b/ConfigEditor/ValueConverters/InvertBooleanConverter.cs new file mode 100644 index 00000000..b33c34d4 --- /dev/null +++ b/ConfigEditor/ValueConverters/InvertBooleanConverter.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows.Data; + +namespace ConfigEditor.ValueConverters +{ + public class InvertBooleanConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + return !(bool)value; + } + + public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + return Convert(value, targetType, parameter, culture); + } + } +} diff --git a/ConfigEditor/ValueConverters/ReadWriteWordsToMaximumConverter.cs b/ConfigEditor/ValueConverters/ReadWriteWordsToMaximumConverter.cs new file mode 100644 index 00000000..cf8b0c18 --- /dev/null +++ b/ConfigEditor/ValueConverters/ReadWriteWordsToMaximumConverter.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows.Data; + +namespace ConfigEditor.ValueConverters +{ + [ValueConversion(typeof(bool), typeof(int))] + public class ReadWriteWordsToMaximumConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + return (bool)value ? int.MaxValue : byte.MaxValue; + } + + public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + return (int)value > byte.MaxValue; + } + } +} diff --git a/ConfigEditor/ValueConverters/SelectedItemToBooleanConverter.cs b/ConfigEditor/ValueConverters/SelectedItemToBooleanConverter.cs new file mode 100644 index 00000000..a4aae7e7 --- /dev/null +++ b/ConfigEditor/ValueConverters/SelectedItemToBooleanConverter.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows.Data; + +namespace ConfigEditor.ValueConverters +{ + [ValueConversion(typeof(object), typeof(bool))] + public class SelectedItemToBooleanConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + return value != null; + } + + public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/ConfigEditor/ViewModels/EventArgs/CommandCompletedEventArgs.cs b/ConfigEditor/ViewModels/EventArgs/CommandCompletedEventArgs.cs new file mode 100644 index 00000000..6283c353 --- /dev/null +++ b/ConfigEditor/ViewModels/EventArgs/CommandCompletedEventArgs.cs @@ -0,0 +1,10 @@ +using System; + +namespace ConfigEditor.ViewModels +{ + public class CommandExecutedEventArgs : EventArgs + { + public bool Success { get; set; } + public Exception Exception { get; set; } + } +} diff --git a/ConfigEditor/ViewModels/EventArgs/DialogEventArgs.cs b/ConfigEditor/ViewModels/EventArgs/DialogEventArgs.cs new file mode 100644 index 00000000..c4f2887b --- /dev/null +++ b/ConfigEditor/ViewModels/EventArgs/DialogEventArgs.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace ConfigEditor.ViewModels +{ + public class DialogEventArgs : EventArgs + { + public bool Update { get; set; } + public T ViewModel { get; private set; } + + public DialogEventArgs(T viewModel) + { + this.ViewModel = viewModel; + } + } +} diff --git a/ConfigEditor/ViewModels/FanConfigViewModel.cs b/ConfigEditor/ViewModels/FanConfigViewModel.cs new file mode 100644 index 00000000..2ddaccc1 --- /dev/null +++ b/ConfigEditor/ViewModels/FanConfigViewModel.cs @@ -0,0 +1,247 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using StagWare.FanControl.Configurations; + +namespace ConfigEditor.ViewModels +{ + public class FanConfigViewModel : ViewModelBase, ICloneable + { + #region Private Fields + + private string fanDisplayName; + private int readRegister; + private int writeRegister; + private int minSpeedValue; + private int maxSpeedValue; + private bool resetRequired; + private int resetValue; + private ObservableCollection temperatureThreshold; + private ObservableCollection fanSpeedOverrides; + private MainViewModel parent; + + #endregion + + #region Properties + + public MainViewModel Parent + { + get + { + return parent; + } + + set + { + if (parent != value) + { + parent = value; + OnPropertyChanged("Parent"); + } + } + } + + public ObservableCollection FanSpeedOverrides + { + get + { + return fanSpeedOverrides; + } + + set + { + if (fanSpeedOverrides != value) + { + fanSpeedOverrides = value; + OnPropertyChanged("Overrides"); + } + } + } + + public ObservableCollection TemperatureThresholds + { + get + { + return temperatureThreshold; + } + + set + { + if (temperatureThreshold != value) + { + temperatureThreshold = value; + OnPropertyChanged("TemperatureThresholds"); + } + } + } + + public int ResetValue + { + get + { + return resetValue; + } + + set + { + if (resetValue != value) + { + resetValue = value; + OnPropertyChanged("ResetValue"); + } + } + } + + public bool ResetRequired + { + get + { + return resetRequired; + } + + set + { + if (resetRequired != value) + { + resetRequired = value; + OnPropertyChanged("ResetRequired"); + } + } + } + + public int MaxSpeedValue + { + get + { + return maxSpeedValue; + } + + set + { + if (maxSpeedValue != value) + { + maxSpeedValue = value; + OnPropertyChanged("MaxSpeedValue"); + OnPropertyChanged("FanSpeedSteps"); + } + } + } + + public int MinSpeedValue + { + get + { + return minSpeedValue; + } + + set + { + if (minSpeedValue != value) + { + minSpeedValue = value; + OnPropertyChanged("MinSpeedValue"); + OnPropertyChanged("FanSpeedSteps"); + } + } + } + + public int WriteRegister + { + get + { + return writeRegister; + } + + set + { + if (writeRegister != value) + { + writeRegister = value; + OnPropertyChanged("WriteRegister"); + } + } + } + + public int ReadRegister + { + get + { + return readRegister; + } + + set + { + if (readRegister != value) + { + readRegister = value; + OnPropertyChanged("ReadRegister"); + } + } + } + + public string FanDisplayName + { + get + { + return fanDisplayName; + } + + set + { + if (fanDisplayName != value) + { + fanDisplayName = value; + OnPropertyChanged("FanDisplayName"); + } + } + } + + public int FanSpeedSteps + { + get + { + return Math.Max(MaxSpeedValue, MinSpeedValue) + - Math.Min(MaxSpeedValue, MinSpeedValue); + } + } + + #endregion + + #region Constructors + + public FanConfigViewModel() + { + this.FanSpeedOverrides = new ObservableCollection(); + this.TemperatureThresholds = new ObservableCollection(); + } + + #endregion + + #region ICloneable implementation + + public object Clone() + { + return new FanConfigViewModel() + { + Parent = this.Parent, + FanDisplayName = this.FanDisplayName, + ReadRegister = this.ReadRegister, + WriteRegister = this.WriteRegister, + MinSpeedValue = this.MinSpeedValue, + MaxSpeedValue = this.MaxSpeedValue, + ResetRequired = this.ResetRequired, + ResetValue = this.ResetValue, + + TemperatureThresholds = new ObservableCollection( + this.TemperatureThresholds.Select(x => x.Clone() as TemperatureThresholdViewModel)), + + FanSpeedOverrides = new ObservableCollection( + this.FanSpeedOverrides.Select(x => x.Clone() as FanSpeedOverrideViewModel)) + }; + } + + #endregion + } +} diff --git a/ConfigEditor/ViewModels/FanSpeedOverrideViewModel.cs b/ConfigEditor/ViewModels/FanSpeedOverrideViewModel.cs new file mode 100644 index 00000000..8f731b6a --- /dev/null +++ b/ConfigEditor/ViewModels/FanSpeedOverrideViewModel.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace ConfigEditor.ViewModels +{ + public class FanSpeedOverrideViewModel : ViewModelBase, ICloneable + { + #region Private Fields + + private int fanSpeedValue; + private double fanSpeedPercentage; + private FanConfigViewModel parent; + + #endregion + + #region Properties + + public double FanSpeedPercentage + { + get + { + return fanSpeedPercentage; + } + + set + { + if (fanSpeedPercentage != value) + { + fanSpeedPercentage = value; + OnPropertyChanged("FanSpeedPercentage"); + OnPropertyChanged("SliderValue"); + } + } + } + + public int FanSpeedValue + { + get + { + return fanSpeedValue; + } + + set + { + if (fanSpeedValue != value) + { + fanSpeedValue = value; + OnPropertyChanged("FanSpeedValue"); + } + } + } + + public FanConfigViewModel Parent + { + get + { + return parent; + } + + set + { + if (parent != value) + { + parent = value; + OnPropertyChanged("Parent"); + } + } + } + + public double SliderValue + { + get { return (Parent.FanSpeedSteps * FanSpeedPercentage) / 100.0; } + set { FanSpeedPercentage = (value / Parent.FanSpeedSteps) * 100.0; } + } + + #endregion + + #region ICloneable implementation + + public object Clone() + { + return new FanSpeedOverrideViewModel() + { + FanSpeedPercentage = this.FanSpeedPercentage, + FanSpeedValue = this.FanSpeedValue, + Parent = this.Parent + }; + } + + #endregion + } +} diff --git a/ConfigEditor/ViewModels/MainViewModel.cs b/ConfigEditor/ViewModels/MainViewModel.cs new file mode 100644 index 00000000..d8de7ca5 --- /dev/null +++ b/ConfigEditor/ViewModels/MainViewModel.cs @@ -0,0 +1,713 @@ +using ConfigEditor.Commands; +using StagWare.FanControl.Configurations; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Xml.Serialization; + +namespace ConfigEditor.ViewModels +{ + public class MainViewModel : ViewModelBase + { + #region Constants + + private const string ConfigsDirectoryName = "Configs"; + + #endregion + + #region Private Fields + + private FanControlConfigManager configManager; + + #region Property Backing Fields + + private ObservableCollection configNames; + private string selectedConfigName; + private string notebookModel; + private int ecPollInterval; + private int criticalTemperature; + private bool readWriteWords; + private ObservableCollection fanConfigs; + private ObservableCollection registerWriteConfigs; + + #endregion + + #region Commands Backing Fields + + private RelayCommand selectConfigCommand; + private RelayCommand createNewConfigCommand; + private RelayCommand saveConfigCommand; + private RelayCommand saveConfigAsCommand; + private RelayCommand deleteConfigCommand; + private RelayCommand importConfigCommand; + + #endregion + + #endregion + + #region Events + + public event EventHandler> RequestingConfigName; + public event EventHandler> RequestingConfigPath; + public event EventHandler SaveConfigCommandExecuted; + public event EventHandler ImportConfigError; + + #endregion + + #region Properties + + #region Model Data + + public ObservableCollection RegisterWriteConfigs + { + get + { + return registerWriteConfigs; + } + + set + { + if (registerWriteConfigs != value) + { + registerWriteConfigs = value; + OnPropertyChanged("RegisterWriteConfigs"); + } + } + } + + public ObservableCollection FanConfigs + { + get + { + return fanConfigs; + } + + set + { + if (fanConfigs != value) + { + fanConfigs = value; + OnPropertyChanged("FanConfigs"); + } + } + } + + public bool ReadWriteWords + { + get + { + return readWriteWords; + } + + set + { + if (readWriteWords != value) + { + readWriteWords = value; + OnPropertyChanged("ReadWriteWords"); + } + } + } + + public int CriticalTemperature + { + get + { + return criticalTemperature; + } + + set + { + if (criticalTemperature != value) + { + criticalTemperature = value; + OnPropertyChanged("CriticalTemperature"); + } + } + } + + public int EcPollInterval + { + get + { + return ecPollInterval; + } + + set + { + if (ecPollInterval != value) + { + ecPollInterval = value; + OnPropertyChanged("EcPollInterval"); + } + } + } + + public string NotebookModel + { + get + { + return notebookModel; + } + + set + { + if (notebookModel != value) + { + notebookModel = value; + OnPropertyChanged("NotebookModel"); + } + } + } + + public string SelectedConfigName + { + get + { + return selectedConfigName; + } + + set + { + if (selectedConfigName != value) + { + selectedConfigName = value; + OnPropertyChanged("SelectedConfigName"); + } + } + } + + public ObservableCollection ConfigNames + { + get + { + return configNames; + } + + set + { + if (configNames != value) + { + configNames = value; + OnPropertyChanged("ConfigNames"); + } + } + } + + #endregion + + #region Commands + + public RelayCommand SelectConfigCommand + { + get + { + if (this.selectConfigCommand == null) + { + this.selectConfigCommand = new RelayCommand(o => + { + string configName = o as string; + + this.configManager.SelectConfig(configName); + UpdateViewModel(); + }); + } + + return this.selectConfigCommand; + } + } + + public RelayCommand ImportConfigCommand + { + get + { + if (this.importConfigCommand == null) + { + this.importConfigCommand = new RelayCommand(o => + { + var vm = new RequestConfigPathViewModel(); + var args = new DialogEventArgs(vm); + + OnRequestingConfigPath(args); + + if (args.Update && vm.IsPathValid) + { + FanControlConfig cfg = null; + + if (TryLoadFanControlConfigV1(vm.ConfigFilePath, out cfg)) + { + string cfgName = cfg.UniqueId; + + if (IsConfigNameValid(cfgName) || TryRequestConfigName(ref cfgName)) + { + AddNewConfig(new FanControlConfigV2(cfg), cfgName); + UpdateViewModel(); + } + } + else + { + OnImportConfigError(EventArgs.Empty); + } + } + }); + } + + return this.importConfigCommand; + } + } + + public RelayCommand DeleteConfigCommand + { + get + { + if (this.deleteConfigCommand == null) + { + this.deleteConfigCommand = new RelayCommand(o => + { + if (this.configManager.SelectedConfig != null) + { + this.configManager.RemoveConfig(this.configManager.SelectedConfigName); + } + + UpdateViewModel(); + }); + } + + return this.deleteConfigCommand; + } + } + + public RelayCommand SaveConfigAsCommand + { + get + { + if (this.saveConfigAsCommand == null) + { + this.saveConfigAsCommand = new RelayCommand(o => + { + try + { + string cfgName = FanControlConfigManager.NotebookModel; + + if (IsConfigNameValid(cfgName) || TryRequestConfigName(ref cfgName)) + { + AddNewConfig(ConvertViewModelToConfig(this), cfgName); + UpdateViewModel(); + + OnSaveConfigCommandExecuted(new CommandExecutedEventArgs() + { + Success = true + }); + } + } + catch (Exception e) + { + OnSaveConfigCommandExecuted(new CommandExecutedEventArgs() + { + Success = false, + Exception = e + }); + } + }); + } + + return this.saveConfigAsCommand; + } + } + + public RelayCommand SaveConfigCommand + { + get + { + if (this.saveConfigCommand == null) + { + this.saveConfigCommand = new RelayCommand(o => + { + try + { + if (string.IsNullOrEmpty(this.SelectedConfigName)) + { + this.SaveConfigAsCommand.Execute(null); + } + else + { + var cfg = ConvertViewModelToConfig(this); + this.configManager.UpdateConfig(this.SelectedConfigName, cfg); + } + + OnSaveConfigCommandExecuted(new CommandExecutedEventArgs() + { + Success = true + }); + } + catch (Exception e) + { + OnSaveConfigCommandExecuted(new CommandExecutedEventArgs() + { + Success = false, + Exception = e + }); + } + }); + } + + return this.saveConfigCommand; + } + } + + public RelayCommand CreateNewConfigCommand + { + get + { + if (this.createNewConfigCommand == null) + { + this.createNewConfigCommand = new RelayCommand(o => + { + this.configManager.SelectConfig(null); + UpdateViewModel(); + }); + } + + return this.createNewConfigCommand; + } + } + + #endregion + + #endregion + + #region Constructors + + public MainViewModel() + { + this.FanConfigs = new ObservableCollection(); + this.RegisterWriteConfigs = new ObservableCollection(); + + InitializeConfigManager(); + UpdateViewModel(); + } + + #endregion + + #region Protected Methods + + protected void OnRequestingConfigName(DialogEventArgs e) + { + if (this.RequestingConfigName != null) + { + RequestingConfigName(this, e); + } + } + + protected void OnRequestingConfigPath(DialogEventArgs e) + { + if (this.RequestingConfigPath != null) + { + RequestingConfigPath(this, e); + } + } + + protected void OnSaveConfigCommandExecuted(CommandExecutedEventArgs e) + { + if (this.SaveConfigCommandExecuted != null) + { + SaveConfigCommandExecuted(this, e); + } + } + + protected void OnImportConfigError(EventArgs e) + { + if (this.ImportConfigError != null) + { + ImportConfigError(this, e); + } + } + + #endregion + + #region Private Methods + + private void InitializeConfigManager() + { + string path = Assembly.GetExecutingAssembly().Location; + path = Path.GetDirectoryName(path); + path = Path.Combine(path, ConfigsDirectoryName); + + this.configManager = new FanControlConfigManager(path); + this.configManager.AutoSelectConfig(); + } + + private bool TryLoadFanControlConfigV1(string configFilePath, out FanControlConfig config) + { + config = null; + + using (FileStream fs = new FileStream(configFilePath, FileMode.Open)) + { + var serializer = new XmlSerializer(typeof(FanControlConfig)); + + try + { + config = (FanControlConfig)serializer.Deserialize(fs); + } + catch + { + return false; + } + } + + return config != null; + } + + private bool IsConfigNameValid(string configName) + { + return !(this.configManager.Contains(configName) + || this.configManager.ConfigFileExists(configName)); + } + + private void AddNewConfig(FanControlConfigV2 config, string configName) + { + if (config == null) + { + throw new ArgumentNullException("config"); + } + + if (!IsConfigNameValid(configName)) + { + throw new ArgumentException("Invalid config name", "configName"); + } + + if (string.IsNullOrWhiteSpace(config.NotebookModel)) + { + config.NotebookModel = FanControlConfigManager.NotebookModel; + } + + if (this.configManager.Contains(configName)) + { + this.configManager.UpdateConfig(configName, config); + } + else + { + this.configManager.AddConfig(config, configName); + } + } + + private bool TryRequestConfigName(ref string configName) + { + var vm = new RequestConfigNameViewModel(this.configManager, configName); + var args = new DialogEventArgs(vm); + + OnRequestingConfigName(args); + + if (args.Update && vm.IsConfigNameValid) + { + configName = vm.ConfigName; + return true; + } + else + { + configName = null; + return false; + } + } + + #region ViewModel to config conversion + + private static FanControlConfigV2 ConvertViewModelToConfig(MainViewModel viewModel) + { + var config = new FanControlConfigV2() + { + CriticalTemperature = viewModel.CriticalTemperature, + EcPollInterval = viewModel.EcPollInterval, + NotebookModel = viewModel.NotebookModel, + ReadWriteWords = viewModel.ReadWriteWords + }; + + if (viewModel.FanConfigs != null) + { + config.FanConfigurations = ConvertViewModelsToFanConfigs(viewModel.FanConfigs); + } + + if (viewModel.RegisterWriteConfigs != null) + { + config.RegisterWriteConfigurations = ConvertViewModelsToRegisterWriteConfigs(viewModel.RegisterWriteConfigs); + } + + return config; + } + + private static List ConvertViewModelsToFanConfigs( + IEnumerable viewModels) + { + List configs = new List(); + + foreach (FanConfigViewModel vm in viewModels) + { + var cfg = new FanConfiguration() + { + FanDisplayName = vm.FanDisplayName, + ReadRegister = vm.ReadRegister, + WriteRegister = vm.WriteRegister, + MinSpeedValue = vm.MinSpeedValue, + MaxSpeedValue = vm.MaxSpeedValue, + ResetRequired = vm.ResetRequired, + FanSpeedResetValue = vm.ResetValue + }; + + if (vm.FanSpeedOverrides != null) + { + cfg.FanSpeedPercentageOverrides = vm.FanSpeedOverrides.Select( + x => new FanSpeedPercentageOverride() + { + FanSpeedPercentage = x.FanSpeedPercentage, + FanSpeedValue = x.FanSpeedValue + }).ToList(); + } + + if (vm.TemperatureThresholds != null) + { + cfg.TemperatureThresholds = vm.TemperatureThresholds.Select( + x => new TemperatureThreshold() + { + DownThreshold = x.DownThreshold, + UpThreshold = x.UpThreshold, + FanSpeed = x.FanSpeedPercentage + }).ToList(); + } + + configs.Add(cfg); + } + + return configs; + } + + private static List ConvertViewModelsToRegisterWriteConfigs( + IEnumerable viewModels) + { + return viewModels.Select( + x => new RegisterWriteConfiguration() + { + Description = x.Description, + Register = x.Register, + Value = x.Value, + ResetRequired = x.ResetRequired, + ResetValue = x.ResetValue, + WriteMode = x.WriteMode, + WriteOccasion = x.WriteOccasion + }).ToList(); + } + + #endregion + + #region ViewModel update + + private void UpdateViewModel() + { + var cfg = this.configManager.SelectedConfig; + var sortedList = this.configManager.ConfigNames.OrderBy(x => x); + this.ConfigNames = new ObservableCollection(sortedList); + + if (cfg == null) + { + ClearViewModel(); + } + else + { + this.SelectedConfigName = this.configManager.SelectedConfigName; + this.CriticalTemperature = cfg.CriticalTemperature; + this.EcPollInterval = cfg.EcPollInterval; + this.NotebookModel = cfg.NotebookModel; + this.ReadWriteWords = cfg.ReadWriteWords; + + if (cfg.RegisterWriteConfigurations != null) + { + var vms = ConvertRegisterWriteConfigsToViewModels(cfg.RegisterWriteConfigurations); + this.RegisterWriteConfigs = new ObservableCollection(vms); + } + + if (cfg.FanConfigurations != null) + { + var vms = ConvertFanConfigsToViewModels(cfg.FanConfigurations); + this.FanConfigs = new ObservableCollection(vms); + } + } + } + + private void ClearViewModel() + { + this.SelectedConfigName = string.Empty; + this.CriticalTemperature = 75; + this.EcPollInterval = 3000; + this.NotebookModel = string.Empty; + this.ReadWriteWords = false; + this.RegisterWriteConfigs.Clear(); + this.FanConfigs.Clear(); + } + + private static IEnumerable ConvertFanConfigsToViewModels( + IEnumerable configs) + { + List viewModels = new List(); + + foreach (FanConfiguration cfg in configs) + { + var vm = new FanConfigViewModel() + { + FanDisplayName = cfg.FanDisplayName, + ReadRegister = cfg.ReadRegister, + WriteRegister = cfg.WriteRegister, + MinSpeedValue = cfg.MinSpeedValue, + MaxSpeedValue = cfg.MaxSpeedValue, + ResetRequired = cfg.ResetRequired, + ResetValue = cfg.FanSpeedResetValue + }; + + if (cfg.FanSpeedPercentageOverrides != null) + { + vm.FanSpeedOverrides = new ObservableCollection( + cfg.FanSpeedPercentageOverrides.Select(x => new FanSpeedOverrideViewModel() + { + FanSpeedPercentage = x.FanSpeedPercentage, + FanSpeedValue = x.FanSpeedValue + })); + } + + if (cfg.TemperatureThresholds != null) + { + vm.TemperatureThresholds = new ObservableCollection( + cfg.TemperatureThresholds.Select(x => new TemperatureThresholdViewModel() + { + UpThreshold = x.UpThreshold, + DownThreshold = x.DownThreshold, + FanSpeedPercentage = x.FanSpeed + })); + } + + viewModels.Add(vm); + } + + return viewModels; + } + + private static IEnumerable ConvertRegisterWriteConfigsToViewModels( + IEnumerable configs) + { + return configs.Select(x => new RegisterWriteConfigViewModel() + { + Description = x.Description, + Register = x.Register, + Value = x.Value, + WriteMode = x.WriteMode, + WriteOccasion = x.WriteOccasion, + ResetRequired = x.ResetRequired, + ResetValue = x.ResetValue + }); + } + + #endregion + + #endregion + } +} diff --git a/ConfigEditor/ViewModels/RegisterWriteConfigViewModel.cs b/ConfigEditor/ViewModels/RegisterWriteConfigViewModel.cs new file mode 100644 index 00000000..7953a8e0 --- /dev/null +++ b/ConfigEditor/ViewModels/RegisterWriteConfigViewModel.cs @@ -0,0 +1,164 @@ +using StagWare.FanControl.Configurations; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace ConfigEditor.ViewModels +{ + public class RegisterWriteConfigViewModel : ViewModelBase, ICloneable + { + #region Private Fields + + private string description; + private RegisterWriteMode writeMode; + private RegisterWriteOccasion writeOccasion; + private int register; + private int val; + private bool resetRequired; + private int resetValue; + + #endregion + + #region Properties + + public int ResetValue + { + get + { + return resetValue; + } + + set + { + if (resetValue != value) + { + resetValue = value; + OnPropertyChanged("ResetValue"); + } + } + } + + public bool ResetRequired + { + get + { + return resetRequired; + } + + set + { + if (resetRequired != value) + { + resetRequired = value; + OnPropertyChanged("ResetRequired"); + } + } + } + + public int Value + { + get + { + return val; + } + + set + { + if (val != value) + { + val = value; + OnPropertyChanged("Value"); + } + } + } + + public int Register + { + get + { + return register; + } + + set + { + if (register != value) + { + register = value; + OnPropertyChanged("Register"); + } + } + } + + public RegisterWriteOccasion WriteOccasion + { + get + { + return writeOccasion; + } + + set + { + if (writeOccasion != value) + { + writeOccasion = value; + OnPropertyChanged("WriteOccasion"); + } + } + } + + public RegisterWriteMode WriteMode + { + get + { + return writeMode; + } + + set + { + if (writeMode != value) + { + writeMode = value; + OnPropertyChanged("WriteMode"); + } + } + } + + public string Description + { + get + { + return description; + } + + set + { + if (description != value) + { + description = value; + OnPropertyChanged("Description"); + } + } + } + + #endregion + + #region ICloneable implementation + + public object Clone() + { + return new RegisterWriteConfigViewModel() + { + Description = this.Description, + Register = this.Register, + Value = this.Value, + WriteMode = this.WriteMode, + WriteOccasion = this.WriteOccasion, + ResetRequired = this.ResetRequired, + ResetValue = this.ResetValue + }; + } + + #endregion + } +} diff --git a/ConfigEditor/ViewModels/RequestConfigNameViewModel.cs b/ConfigEditor/ViewModels/RequestConfigNameViewModel.cs new file mode 100644 index 00000000..3fe2e0e7 --- /dev/null +++ b/ConfigEditor/ViewModels/RequestConfigNameViewModel.cs @@ -0,0 +1,90 @@ +using StagWare.FanControl.Configurations; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Media; + +namespace ConfigEditor.ViewModels +{ + public class RequestConfigNameViewModel : ViewModelBase + { + #region Private Fields + + private FanControlConfigManager configManager; + private string configName; + + #endregion + + #region Constructors + + public RequestConfigNameViewModel(FanControlConfigManager configManager, string configNameDefault) + { + this.configManager = configManager; + this.ConfigName = configNameDefault; + + UpdateIsConfigNameUniqueProperty(); + UpdateIsConfigNameValidProperty(); + } + + #endregion + + #region Properties + + public string ConfigName + { + get + { + return configName; + } + + set + { + if (configName != value) + { + configName = value; + OnPropertyChanged("ConfigName"); + + UpdateIsConfigNameUniqueProperty(); + UpdateIsConfigNameValidProperty(); + } + } + } + + public bool IsConfigNameUnique { get; private set; } + public bool IsConfigNameValid { get; private set; } + + #endregion + + #region Private Methods + + private void UpdateIsConfigNameUniqueProperty() + { + bool isUnique = configManager != null + && !configManager.Contains(this.ConfigName) + && !configManager.ConfigFileExists(this.ConfigName); + + if (isUnique != IsConfigNameUnique) + { + IsConfigNameUnique = isUnique; + OnPropertyChanged("IsConfigNameUnique"); + } + } + + private void UpdateIsConfigNameValidProperty() + { + bool isValid = !string.IsNullOrWhiteSpace(this.ConfigName) + && this.ConfigName.IndexOfAny(FanControlConfigManager.InvalidFileNameChars) == -1; + + if (isValid != IsConfigNameValid) + { + IsConfigNameValid = isValid; + OnPropertyChanged("IsConfigNameValid"); + } + } + + #endregion + } +} diff --git a/ConfigEditor/ViewModels/RequestConfigPathViewModel.cs b/ConfigEditor/ViewModels/RequestConfigPathViewModel.cs new file mode 100644 index 00000000..b60eee13 --- /dev/null +++ b/ConfigEditor/ViewModels/RequestConfigPathViewModel.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace ConfigEditor.ViewModels +{ + public class RequestConfigPathViewModel + { + private const string ConfigFileExt = "config"; + + public string ConfigFileExtension + { + get + { + return ConfigFileExt; + } + } + + public bool IsPathValid + { + get + { + return File.Exists(this.ConfigFilePath); + } + } + + public string ConfigFilePath { get; set; } + } +} diff --git a/ConfigEditor/ViewModels/TemperatureThresholdViewModel.cs b/ConfigEditor/ViewModels/TemperatureThresholdViewModel.cs new file mode 100644 index 00000000..2501f643 --- /dev/null +++ b/ConfigEditor/ViewModels/TemperatureThresholdViewModel.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace ConfigEditor.ViewModels +{ + public class TemperatureThresholdViewModel : ViewModelBase, ICloneable + { + #region Private Fields + + private int upThreshold; + private int downThreshold; + private double fanSpeedPercentage; + private FanConfigViewModel parent; + + #endregion + + #region Properties + + public double FanSpeedPercentage + { + get + { + return fanSpeedPercentage; + } + + set + { + if (fanSpeedPercentage != value) + { + fanSpeedPercentage = value; + OnPropertyChanged("FanSpeedPercentage"); + OnPropertyChanged("SliderValue"); + } + } + } + + public int DownThreshold + { + get + { + return downThreshold; + } + + set + { + if (downThreshold != value) + { + downThreshold = value; + OnPropertyChanged("DownThreshold"); + } + } + } + + public int UpThreshold + { + get + { + return upThreshold; + } + + set + { + if (upThreshold != value) + { + upThreshold = value; + OnPropertyChanged("UpThreshold"); + } + } + } + + public FanConfigViewModel Parent + { + get + { + return parent; + } + + set + { + if (parent != value) + { + parent = value; + OnPropertyChanged("Parent"); + } + } + } + + public double SliderValue + { + get { return (Parent.FanSpeedSteps * FanSpeedPercentage) / 100.0; } + set { FanSpeedPercentage = (value / Parent.FanSpeedSteps) * 100.0; } + } + + #endregion + + #region ICloneable implementation + + public object Clone() + { + return new TemperatureThresholdViewModel() + { + DownThreshold = this.DownThreshold, + UpThreshold = this.UpThreshold, + FanSpeedPercentage = this.FanSpeedPercentage, + Parent = this.Parent + }; + } + + #endregion + } +} diff --git a/ConfigEditor/ViewModels/ViewModelBase.cs b/ConfigEditor/ViewModels/ViewModelBase.cs new file mode 100644 index 00000000..9382e92d --- /dev/null +++ b/ConfigEditor/ViewModels/ViewModelBase.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; + +namespace ConfigEditor.ViewModels +{ + public abstract class ViewModelBase : INotifyPropertyChanged + { + #region INotifyPropertyChanged implementation + + public event PropertyChangedEventHandler PropertyChanged; + + protected void OnPropertyChanged(string propertyName) + { + if (this.PropertyChanged != null) + { + PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); + } + } + + #endregion + } +} diff --git a/ConfigEditor/Windows/FanConfigWindow.xaml b/ConfigEditor/Windows/FanConfigWindow.xaml new file mode 100644 index 00000000..2312500d --- /dev/null +++ b/ConfigEditor/Windows/FanConfigWindow.xaml @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ConfigEditor/Windows/MainWindow.xaml.cs b/ConfigEditor/Windows/MainWindow.xaml.cs new file mode 100644 index 00000000..3983c847 --- /dev/null +++ b/ConfigEditor/Windows/MainWindow.xaml.cs @@ -0,0 +1,370 @@ +using ConfigEditor.ViewModels; +using Ookii.Dialogs.Wpf; +using StagWare.FanControl.Configurations; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Drawing; +using System.Windows; +using System.Windows.Controls; + +namespace ConfigEditor.Windows +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window + { + #region Constants + + private readonly Style MessageBoxErrorStyle; + private readonly Style MessageBoxInfoStyle; + + #endregion + + #region Private Fields + + private Dictionary currentlyEditedViewModels; + + #endregion + + #region Dependency Properties + + public bool IsEditing + { + get { return (bool)GetValue(IsEditingProperty); } + } + + internal static readonly DependencyPropertyKey IsEditingPropertyKey = + DependencyProperty.RegisterReadOnly("IsEditing", typeof(bool), typeof(MainWindow), new PropertyMetadata(false)); + + public static readonly DependencyProperty IsEditingProperty = IsEditingPropertyKey.DependencyProperty; + + #endregion + + #region Constructors + + public MainWindow() + { + InitializeComponent(); + + this.MessageBoxErrorStyle = new Style(typeof(Xceed.Wpf.Toolkit.MessageBox)); + this.MessageBoxErrorStyle.Setters.Add(new Setter() + { + Property = Xceed.Wpf.Toolkit.MessageBox.ImageSourceProperty, + Value = SystemIcons.Error.ToImageSource() + }); + + this.MessageBoxInfoStyle = new Style(typeof(Xceed.Wpf.Toolkit.MessageBox)); + this.MessageBoxInfoStyle.Setters.Add(new Setter() + { + Property = Xceed.Wpf.Toolkit.MessageBox.ImageSourceProperty, + Value = SystemIcons.Information.ToImageSource() + }); + + this.currentlyEditedViewModels = new Dictionary(); + + var vm = new MainViewModel(); + vm.RequestingConfigName += vm_RequestingConfigName; + vm.RequestingConfigPath += vm_RequestingConfigPath; + vm.SaveConfigCommandExecuted += vm_SaveConfigCommandExecuted; + vm.ImportConfigError += vm_ImportConfigError; + + this.DataContext = vm; + } + + #endregion + + #region Private Methods + + private void AddViewModel(Collection collection, T viewModel, NonModalDialogWindow window) where T : ViewModelBase + { + window.Closed += (sender, e) => + { + if (window.ApplyChanges) + { + collection.Add(viewModel); + } + + this.currentlyEditedViewModels.Remove(viewModel); + this.SetValue(MainWindow.IsEditingPropertyKey, this.currentlyEditedViewModels.Count > 0); + }; + + this.currentlyEditedViewModels.Add(viewModel, window); + this.SetValue(MainWindow.IsEditingPropertyKey, this.currentlyEditedViewModels.Count > 0); + window.Show(); + } + + private void EditViewModel(Collection collection, T viewModel, NonModalDialogWindow window) where T : ViewModelBase + { + if (this.currentlyEditedViewModels.ContainsKey(viewModel)) + { + this.currentlyEditedViewModels[viewModel].Activate(); + } + else + { + this.currentlyEditedViewModels.Add(viewModel, window); + this.SetValue(MainWindow.IsEditingPropertyKey, this.currentlyEditedViewModels.Count > 0); + + window.Closed += (sender, e) => + { + if (window.ApplyChanges) + { + collection.Replace(viewModel, (T)window.DataContext); + } + + this.currentlyEditedViewModels.Remove(viewModel); + this.SetValue(MainWindow.IsEditingPropertyKey, this.currentlyEditedViewModels.Count > 0); + }; + + window.Show(); + } + } + + private void RemoveViewModel(Collection collection, T viewModel) where T : ViewModelBase + { + if (this.currentlyEditedViewModels.ContainsKey(viewModel)) + { + this.currentlyEditedViewModels[viewModel].Close(); + this.currentlyEditedViewModels.Remove(viewModel); + this.SetValue(MainWindow.IsEditingPropertyKey, this.currentlyEditedViewModels.Count > 0); + } + + if (this.DataContext is MainViewModel) + { + collection.Remove(viewModel); + } + } + + private void BeginEditFanConfig() + { + var dc = this.DataContext as MainViewModel; + var vm = this.fanConfigsGrid.SelectedValue as FanConfigViewModel; + + if (vm != null && dc != null) + { + var clonedViewModel = (FanConfigViewModel)vm.Clone(); + clonedViewModel.Parent = dc; + + var wnd = new FanConfigWindow() + { + DataContext = clonedViewModel, + Owner = this + }; + + EditViewModel(dc.FanConfigs, vm, wnd); + } + } + + private void BeginEditRegisterWriteConfig() + { + var dc = this.DataContext as MainViewModel; + var vm = this.registerWriteConfigsGrid.SelectedValue as RegisterWriteConfigViewModel; + + if (vm != null && dc != null) + { + var clonedViewModel = vm.Clone() as RegisterWriteConfigViewModel; + + var wnd = new RegisterWriteConfigWindow() + { + DataContext = clonedViewModel, + Owner = this + }; + + EditViewModel(dc.RegisterWriteConfigs, vm, wnd); + } + } + + #endregion + + #region Event Handlers + + #region ViewModel + + void vm_RequestingConfigName(object sender, DialogEventArgs e) + { + var dialog = new RequestConfigNameWindow() + { + DataContext = e.ViewModel, + Owner = this + }; + + if (dialog.ShowDialog() == true) + { + e.Update = true; + } + } + + void vm_RequestingConfigPath(object sender, DialogEventArgs e) + { + var dialog = new VistaOpenFileDialog() + { + CheckFileExists = true, + CheckPathExists = true, + Filter = string.Format("NBFC config file V1(*.{0})|*.{0}", e.ViewModel.ConfigFileExtension), + DefaultExt = e.ViewModel.ConfigFileExtension, + Multiselect = false, + Title = "Please select a config file" + }; + + if (dialog.ShowDialog(this) == true) + { + e.Update = true; + e.ViewModel.ConfigFilePath = dialog.FileName; + } + } + + void vm_SaveConfigCommandExecuted(object sender, CommandExecutedEventArgs e) + { + if (e.Success) + { + Xceed.Wpf.Toolkit.MessageBox.Show( + this, + "Config saved successfully", + "Success", + MessageBoxButton.OK, + MessageBoxInfoStyle); + } + else + { + Xceed.Wpf.Toolkit.MessageBox.Show( + this, + "Config could not be saved.\n\n" + e.Exception.Message, + "Error", + MessageBoxButton.OK, + MessageBoxErrorStyle); + } + } + + void vm_ImportConfigError(object sender, System.EventArgs e) + { + Xceed.Wpf.Toolkit.MessageBox.Show( + "The selected file could not be imported. Maybe it is not valid or you don't have read permissions", + "Import failed", + MessageBoxButton.OK, + MessageBoxErrorStyle); + } + + #endregion + + #region Notebook Model Buttons + + private void insertNotebookModel_Click(object sender, RoutedEventArgs e) + { + this.notebookModel.Text = FanControlConfigManager.NotebookModel; + } + + private void lock_Checked(object sender, RoutedEventArgs e) + { + var style = new Style(typeof(Xceed.Wpf.Toolkit.MessageBox)); + style.Setters.Add(new Setter() + { + Property = Xceed.Wpf.Toolkit.MessageBox.ImageSourceProperty, + Value = SystemIcons.Warning.ToImageSource() + }); + + Xceed.Wpf.Toolkit.MessageBox.Show( + this, + "A valid notebook model string is required in order that automatic config selection works correctly." + + "\nPlease make sure you enter a valid model sting.", + "Warning", MessageBoxButton.OK, style); + } + + #endregion + + #region Fan Configs + + private void addFanConfig_Click(object sender, RoutedEventArgs e) + { + var dc = this.DataContext as MainViewModel; + + if (dc != null) + { + var vm = new FanConfigViewModel() + { + Parent = dc + }; + + var wnd = new FanConfigWindow() + { + DataContext = vm, + Owner = this + }; + + AddViewModel(dc.FanConfigs, vm, wnd); + } + } + + private void editFanConfig_Click(object sender, RoutedEventArgs e) + { + BeginEditFanConfig(); + } + + private void removeFanConfig_Click(object sender, RoutedEventArgs e) + { + var dc = this.DataContext as MainViewModel; + var vm = this.fanConfigsGrid.SelectedValue as FanConfigViewModel; + + if (vm != null && dc != null) + { + RemoveViewModel(dc.FanConfigs, vm); + } + } + + private void fanConfigsGrid_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e) + { + if (e.MouseDevice.IsMouseOverElement(typeof(DataGridCell))) + { + BeginEditFanConfig(); + } + } + + #endregion + + #region Register Write Configs + + private void addRegisterWriteConfig_Click(object sender, RoutedEventArgs e) + { + var dc = this.DataContext as MainViewModel; + + if (dc != null) + { + var vm = new RegisterWriteConfigViewModel(); + var wnd = new RegisterWriteConfigWindow() + { + DataContext = vm, + Owner = this + }; + + AddViewModel(dc.RegisterWriteConfigs, vm, wnd); + } + } + + private void editRegisterWriteConfig_Click(object sender, RoutedEventArgs e) + { + BeginEditRegisterWriteConfig(); + } + + private void removeRegisterWriteConfig_Click(object sender, RoutedEventArgs e) + { + var dc = this.DataContext as MainViewModel; + var vm = this.registerWriteConfigsGrid.SelectedValue as RegisterWriteConfigViewModel; + + if (vm != null && dc != null) + { + RemoveViewModel(dc.RegisterWriteConfigs, vm); + } + } + + private void registerWriteConfigsGrid_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e) + { + if (e.MouseDevice.IsMouseOverElement(typeof(DataGridCell))) + { + BeginEditRegisterWriteConfig(); + } + } + + #endregion + + #endregion + } +} diff --git a/ConfigEditor/Windows/NonModalDialogWindow.cs b/ConfigEditor/Windows/NonModalDialogWindow.cs new file mode 100644 index 00000000..cfa5a9c6 --- /dev/null +++ b/ConfigEditor/Windows/NonModalDialogWindow.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; + +namespace ConfigEditor.Windows +{ + public abstract class NonModalDialogWindow : Window + { + public bool ApplyChanges { get; set; } + } +} diff --git a/ConfigEditor/Windows/RegisterWriteConfigWindow.xaml b/ConfigEditor/Windows/RegisterWriteConfigWindow.xaml new file mode 100644 index 00000000..0a8c3c53 --- /dev/null +++ b/ConfigEditor/Windows/RegisterWriteConfigWindow.xaml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #(loc.Title) + + #(loc.InstallHeader) + #(loc.InstallMessage) + #(loc.InstallVersion) + + + + + + #(loc.Title) + + #(loc.OptionsHeader) + #(loc.OptionsLocationLabel) + + + + + + + + #(loc.Title) + + #(loc.ProgressHeader) + #(loc.ProgressLabel) + #(loc.OverallProgressPackageText) + + + + + #(loc.Title) + + #(loc.ModifyHeader) + + + + + + #(loc.Title) + + #(loc.SuccessHeader) + + #(loc.SuccessRestartText) + + + + + #(loc.Title) + + #(loc.FailureHeader) + #(loc.FailureHyperlinkLogText) + + #(loc.FailureRestartText) + + + + \ No newline at end of file diff --git a/NbfcBootstrapper/Resources/HyperlinkTheme.wxl b/NbfcBootstrapper/Resources/HyperlinkTheme.wxl new file mode 100644 index 00000000..955ba616 --- /dev/null +++ b/NbfcBootstrapper/Resources/HyperlinkTheme.wxl @@ -0,0 +1,49 @@ + + + [WixBundleName] Setup + [WixBundleName] + Welcome + Setup will install [WixBundleName] on your computer. Click install to continue, options to set the install directory or Close to exit. + Version [WixBundleVersion] + Are you sure you want to cancel? + Setup Help + /install | /repair | /uninstall | /layout [directory] - installs, repairs, uninstalls or creates a complete local copy of the bundle in directory. Install is the default. + +/passive | /quiet - displays minimal UI with no prompts or displays no UI and no prompts. By default UI and all prompts are displayed. + +/norestart - suppress any attempts to restart. By default UI will prompt before restart. + +/log log.txt - logs to a specific file. By default a log file is created in %TEMP%. + &Close + [WixBundleName] <a href="#">license terms</a>. + I &agree to the license terms and conditions + &Options + &Install + &Close + Version [WixBundleVersion] <a href="#">upgrade available</a> + Setup Options + Install location: + &Browse... + Database location: + B&rowse... + &OK + &Cancel + Setup Progress + Processing: + Initializing... + &Cancel + Modify Setup + &Repair + &Uninstall + &Close + Setup Successful + &Launch + You must restart your computer before you can use the software. + &Restart + &Close + Setup Failed + One or more issues caused the setup to fail. Please fix the issues and then retry setup. For more information see the <a href="#">log file</a>. + You must restart your computer to complete the rollback of the software. + &Restart + &Close + \ No newline at end of file diff --git a/NbfcBootstrapper/Resources/logo.png b/NbfcBootstrapper/Resources/logo.png new file mode 100644 index 00000000..38f0457d Binary files /dev/null and b/NbfcBootstrapper/Resources/logo.png differ diff --git a/NbfcBootstrapper/Resources/logoside.png b/NbfcBootstrapper/Resources/logoside.png new file mode 100644 index 00000000..8ca7453c Binary files /dev/null and b/NbfcBootstrapper/Resources/logoside.png differ diff --git a/NbfcService/NbfcService.Designer.cs b/NbfcService/NbfcService.Designer.cs new file mode 100644 index 00000000..aa54969a --- /dev/null +++ b/NbfcService/NbfcService.Designer.cs @@ -0,0 +1,40 @@ +namespace NbfcService +{ + partial class NoteBookFanControlService + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + // + // NoteBookFanControlService + // + this.ServiceName = "NoteBookFanControlService"; + + } + + #endregion + } +} diff --git a/NbfcService/NbfcService.cs b/NbfcService/NbfcService.cs new file mode 100644 index 00000000..32dcbf15 --- /dev/null +++ b/NbfcService/NbfcService.cs @@ -0,0 +1,133 @@ +using StagWare.FanControl.Service; +using System; +using System.IO; +using System.Reflection; +using System.ServiceModel; +using System.ServiceProcess; +using System.Text; +using System.Threading; + +namespace NbfcService +{ + public partial class NoteBookFanControlService : ServiceBase + { + #region Private Fields + + private ServiceHost host; + + #endregion + + #region Constructors + + public NoteBookFanControlService() + { + AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; + + InitializeComponent(); + } + + #endregion + + #region Main + + public void Main() + { + ServiceBase.Run(new NoteBookFanControlService()); + } + + #endregion + + #region Overrides + + protected override void OnStart(string[] args) + { + StopServiceHost(); + + host = new ServiceHost(typeof(FanControlService)); + host.Open(); + } + + protected override void OnStop() + { + StopServiceHost(); + } + + protected override void OnShutdown() + { + //// base.RequestAdditionalTime(2000); + + StopServiceHost(); + base.OnShutdown(); + } + + #endregion + + #region Private Methods + + private void StopServiceHost() + { + if (host != null) + { + host.Close(); + host = null; + } + } + + #endregion + + #region Debug + + private static void LogException(string fileName, Exception e) + { + if (e == null) + { + return; + } + + string path = Assembly.GetExecutingAssembly().Location; + path = Path.GetDirectoryName(path); + path = Path.Combine(path, fileName); + + StringBuilder exception = new StringBuilder(); + exception.AppendLine("-------------------------------------------------------"); + exception.AppendFormat("Timestamp: {0}{1}", DateTime.Now.ToString(), Environment.NewLine); + + if (e.TargetSite != null) + { + exception.AppendFormat("Method Name: {0}{1}", e.TargetSite.Name, Environment.NewLine); + + if (e.TargetSite.DeclaringType != null) + { + exception.AppendFormat("Declaring Type: {0}{1}", e.TargetSite.DeclaringType.Name, Environment.NewLine); + } + } + + exception.AppendFormat("Message: {0}{1}", e.Message, Environment.NewLine); + + Exception inner = e.InnerException; + + while (inner != null) + { + exception.AppendFormat("Inner Message: {0}{1}", inner.Message, Environment.NewLine); + inner = inner.InnerException; + } + + exception.AppendFormat("Source: {0}{1}", e.Source, Environment.NewLine); + exception.AppendFormat("StackTrace: {0}{1}", e.StackTrace, Environment.NewLine); + + File.AppendAllText(path, exception.ToString()); + } + + private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) + { + var ex = e.ExceptionObject as Exception; + + if (ex != null) + { + LogException("Exceptions.log", ex); + } + } + + #endregion + } +} diff --git a/NbfcService/NbfcService.csproj b/NbfcService/NbfcService.csproj new file mode 100644 index 00000000..0e758aeb --- /dev/null +++ b/NbfcService/NbfcService.csproj @@ -0,0 +1,144 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {820ABB59-7F86-4D7F-89C9-8F7DA013D992} + WinExe + Properties + NbfcService + NbfcService + v4.0 + Client + 512 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + NbfcService.Program + + + + + + + AnyCPU + bin\Debug\ + + + AnyCPU + bin\Release\ + + + + + + + + + + + + + + + + + Component + + + NbfcService.cs + + + + Component + + + ProjectInstaller.cs + + + + + + NbfcService.cs + + + ProjectInstaller.cs + + + + + {15b3e0d2-6217-493a-a690-158c497f5318} + StagWare.FanControl.Service + + + + + Designer + + + + + False + Microsoft .NET Framework 4 Client Profile %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + false + + + False + Windows Installer 4.5 + true + + + + + \ No newline at end of file diff --git a/NbfcService/NbfcService.resx b/NbfcService/NbfcService.resx new file mode 100644 index 00000000..e5858cc2 --- /dev/null +++ b/NbfcService/NbfcService.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + False + + \ No newline at end of file diff --git a/NbfcService/Program.cs b/NbfcService/Program.cs new file mode 100644 index 00000000..9e5af144 --- /dev/null +++ b/NbfcService/Program.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.ServiceProcess; +using System.Text; + +namespace NbfcService +{ + public static class Program + { + /// + /// The main entry point for the application. + /// + public static void Main() + { + ServiceBase[] servicesToRun = new ServiceBase[] + { + new NoteBookFanControlService() + }; + + ServiceBase.Run(servicesToRun); + } + } +} diff --git a/NbfcService/ProjectInstaller.Designer.cs b/NbfcService/ProjectInstaller.Designer.cs new file mode 100644 index 00000000..20530b22 --- /dev/null +++ b/NbfcService/ProjectInstaller.Designer.cs @@ -0,0 +1,61 @@ +namespace NbfcService +{ + partial class ProjectInstaller + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.fanControlServiceProcessInstaller = new System.ServiceProcess.ServiceProcessInstaller(); + this.fanControlServiceInstaller = new System.ServiceProcess.ServiceInstaller(); + // + // fanControlServiceProcessInstaller + // + this.fanControlServiceProcessInstaller.Account = System.ServiceProcess.ServiceAccount.LocalSystem; + this.fanControlServiceProcessInstaller.Password = null; + this.fanControlServiceProcessInstaller.Username = null; + // + // fanControlServiceInstaller + // + this.fanControlServiceInstaller.Description = "Allows to control the fans on many different notebook models via user defined con" + + "figuration files. "; + this.fanControlServiceInstaller.DisplayName = "NoteBook FanControl Service"; + this.fanControlServiceInstaller.ServiceName = "NbfcService"; + this.fanControlServiceInstaller.StartType = System.ServiceProcess.ServiceStartMode.Automatic; + // + // ProjectInstaller + // + this.Installers.AddRange(new System.Configuration.Install.Installer[] { + this.fanControlServiceProcessInstaller, + this.fanControlServiceInstaller}); + + } + + #endregion + + private System.ServiceProcess.ServiceProcessInstaller fanControlServiceProcessInstaller; + private System.ServiceProcess.ServiceInstaller fanControlServiceInstaller; + } +} \ No newline at end of file diff --git a/NbfcService/ProjectInstaller.cs b/NbfcService/ProjectInstaller.cs new file mode 100644 index 00000000..66a9eab9 --- /dev/null +++ b/NbfcService/ProjectInstaller.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Configuration.Install; +using System.Linq; +using System.ServiceProcess; + +namespace NbfcService +{ + [RunInstaller(true)] + public partial class ProjectInstaller : System.Configuration.Install.Installer + { + public ProjectInstaller() + { + InitializeComponent(); + + // StagWare.Configurations.FanControlConfigManager uses WMI to get notebook model + // update: Service does not call the NotebookModel getter + + // this.fanControlServiceInstaller.ServicesDependedOn = new string[] + // { + // "Winmgmt" + // }; + } + } +} diff --git a/NbfcService/ProjectInstaller.resx b/NbfcService/ProjectInstaller.resx new file mode 100644 index 00000000..61f1f2ad --- /dev/null +++ b/NbfcService/ProjectInstaller.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 56 + + + 26, 98 + + + False + + \ No newline at end of file diff --git a/NbfcService/Properties/AssemblyInfo.cs b/NbfcService/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..d47a9989 --- /dev/null +++ b/NbfcService/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("NoteBook FanControl Service")] +[assembly: AssemblyDescription("Config based fan control service for notebooks.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Stefan Hirschmann - StagWare")] +[assembly: AssemblyProduct("NoteBook FanControl Service")] +[assembly: AssemblyCopyright("Copyright © 2013 Stefan Hirschmann")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("00f4eb12-95eb-45fa-8488-455c388f3b49")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/NbfcService/app.config b/NbfcService/app.config new file mode 100644 index 00000000..3ce76153 --- /dev/null +++ b/NbfcService/app.config @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NbfcServiceClient/App.xaml b/NbfcServiceClient/App.xaml new file mode 100644 index 00000000..f5ec33e8 --- /dev/null +++ b/NbfcServiceClient/App.xaml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NbfcServiceClient/App.xaml.cs b/NbfcServiceClient/App.xaml.cs new file mode 100644 index 00000000..4e9c893c --- /dev/null +++ b/NbfcServiceClient/App.xaml.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Globalization; +using System.Linq; +using System.Windows; +using System.Windows.Markup; + +namespace NbfcServiceClient +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + public App() + { + FrameworkElement.LanguageProperty.OverrideMetadata( + typeof(FrameworkElement), + new FrameworkPropertyMetadata( + XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag))); + } + } +} diff --git a/NbfcServiceClient/AppSettings.cs b/NbfcServiceClient/AppSettings.cs new file mode 100644 index 00000000..71a2def2 --- /dev/null +++ b/NbfcServiceClient/AppSettings.cs @@ -0,0 +1,608 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Globalization; +using System.IO; +using System.Reflection; +using System.Xml.Serialization; + +namespace StagWare.Settings +{ + public sealed class AppSettings + { + #region Settings - Properties + + /* Put your properties here + * + * Properties must be public; getters and setters as well. + * You may assign any of the following attributes to your properties + * to control how they are handled. + * + * [LoadDefaultsIgnore] + * If this attribute is assigned, the affected property + * will be ignored on the call of LoadDefaults(), thus it will + * retain its value. + * + * + * [PropertyDefaultValue(object value)] + * Assigns the value to the property. + * Will only work for value types. + * + * + * [PropertyDefaultValue(Type propertyType, params object[] constructorParameters)] + * Calls the constructor which matches + * the specified parameters. + * If no parameters are provided, + * a parameterless constructor will be called. + * + * + * You can also encapsulate types with no public properties (e.g. Color) in XmlWrapper + * to enable them to be stored in XML settings file. + * This type provides implicit cast operators to obviate casts. + * + * + * Examples: + * + * [PropertyDefaultValue(typeof(XmlWrapper), "Red")] + * public XmlWrapper MyColor { get; set; } + * + * [PropertyDefaultValue(typeof(XmlWrapper), "Tahoma, 8.25pt")] + * public XmlWrapper MyFont { get; set; } + */ + + [PropertyDefaultValue(typeof(XmlWrapper), "#FF000000")] + public XmlWrapper TrayIconForegroundColor { get; set; } + + [PropertyDefaultValue(false)] + public bool CloseToTray { get; set; } + + [PropertyDefaultValue(350)] + public double WindowHeight { get; set; } + + [PropertyDefaultValue(430)] + public double WindowWidth { get; set; } + + #endregion + + //---------------------------// + + #region Code behind - DO NOT MODIFY! + + #region Nested Types + + private class Properties + { + #region Singleton instance + + internal static AppSettings Instance; + + #endregion + + #region Private Fields + + private static readonly object SyncRoot = new object(); + + #endregion + + #region Constructors + + private Properties() + { } + + // Explicit static constructor to tell compiler + // not to mark type as 'beforefieldinit'. + static Properties() + { + Reload(); + } + + #endregion + + #region Internal Methods + + internal static void Reload() + { + lock (SyncRoot) + { + Instance = new AppSettings(); + + if (AppSettings.SettingsFileExists) + { + try + { + using (FileStream fs = new FileStream( + Path.Combine( + AppSettings.settingsFileDir, + AppSettings.settingsFileName), + FileMode.Open)) + { + Properties.Instance = (AppSettings)AppSettings.Values.serializer.Deserialize(fs); + } + } + catch + { + OnLoadSettingsFailed(); + } + } + } + } + + #endregion + } + + private class PropertyValue + { + #region Properties + + public Type ValueType { get; set; } + public string ValueName { get; set; } + public object ValueData { get; set; } + + #endregion + + #region Constructor + + public PropertyValue(Type valueType, string valueName, object valueData) + { + this.ValueType = valueType; + this.ValueName = valueName; + this.ValueData = valueData; + } + + #endregion + } + + public class XmlWrapper + { + #region Private Fields + + T wrappedItem; + + #endregion + + #region Constructors + + public XmlWrapper() + { + this.wrappedItem = default(T); + } + + public XmlWrapper(T wrappedItem) + { + this.wrappedItem = wrappedItem; + } + + public XmlWrapper(string wrappedItemValue) + { + this.Value = wrappedItemValue; + } + + #endregion + + #region Properties + + public string Value + { + get + { + return TypeDescriptor.GetConverter(typeof(T)).ConvertToString( + null, + CultureInfo.InvariantCulture, + wrappedItem); + } + + set + { + wrappedItem = (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFromString( + null, + CultureInfo.InvariantCulture, + value); + } + } + + #endregion + + #region Type Conversion Operators + + public static implicit operator XmlWrapper(T item) + { + if (item != null) + { + return new XmlWrapper(item); + } + else + { + return null; + } + } + + public static implicit operator T(XmlWrapper wrapper) + { + if (wrapper != null) + { + return wrapper.wrappedItem; + } + else + { + return default(T); + } + } + + #endregion + } + + #region Attributes + + [AttributeUsage(AttributeTargets.Property)] + private sealed class LoadDefaultsIgnoreAttribute : Attribute + { + } + + [AttributeUsage(AttributeTargets.Property)] + private sealed class PropertyDefaultValueAttribute : Attribute + { + #region Properties + + public object Value { get; set; } + + #endregion + + #region Constructors + + public PropertyDefaultValueAttribute(object value) + { + this.Value = value; + } + + public PropertyDefaultValueAttribute(Type propertyType, params object[] constructorParameters) + { + Type[] types = new Type[constructorParameters.Length]; + + for (int i = 0; i < constructorParameters.Length; i++) + { + types[i] = constructorParameters[i].GetType(); + } + + ConstructorInfo constructor = propertyType.GetConstructor(types); + + if (constructor != null) + { + this.Value = constructor.Invoke(constructorParameters); + } + else + { + if (types.Length <= 0) + { + string msg = "There ist no default constructor for the type " + propertyType; + + throw new ArgumentException(msg); + } + else + { + string msg = "There ist no default constructor for the type " + + propertyType.ToString() + " which accepts the following arguments: "; + + for (int i = 0; i < types.Length; i++) + { + msg += types[i].ToString(); + + if (i < types.Length - 1) + { + msg += ", "; + } + } + + throw new ArgumentException(msg); + } + } + } + + #endregion + } + + #endregion + + #endregion + + #region Constants + + private const string SettingsFileExtension = ".xml"; + private const string SingletonInstancePropertyName = "Values"; + + #endregion + + #region Private Static Fields + + static string settingsFileDir = GetDefaultSettingsFileDirPath(); + static string settingsFileName = GetDefaultSettingsFileName(); + + #endregion + + #region Private Fields + + List defaults; + List stored; + XmlSerializer serializer; + + #endregion + + #region Static Events + + public static event EventHandler LoadSettingsFailed; + public static event EventHandler SaveSettingsFailed; + + #endregion + + #region Static Properties + + // Singleton instance. + public static AppSettings Values + { + get { return Properties.Instance; } + } + + public static string SettingsDirectoryPath + { + get { return AppSettings.settingsFileDir; } + set { AppSettings.settingsFileDir = value; } + } + + public static string SettingsFileName + { + get { return AppSettings.settingsFileName; } + set { AppSettings.settingsFileName = value; } + } + + public static bool SettingsFileExists + { + get + { + return File.Exists(Path.Combine( + AppSettings.settingsFileDir, AppSettings.settingsFileName)); + } + } + + #endregion + + #region Constructors + + // Hide constructor. (Singleton) + private AppSettings() + { + this.defaults = new List(); + this.stored = new List(); + + // Fill the list of default values. + foreach (PropertyInfo propInfo in this.GetType().GetProperties()) + { + // Assign defaults only to non static properties + MethodInfo methodInfo = propInfo.GetGetMethod(false); + + if (methodInfo == null || methodInfo.IsStatic) + { + continue; + } + + object[] loadDefaultsIgnore = propInfo.GetCustomAttributes(typeof(LoadDefaultsIgnoreAttribute), false); + object[] defaultValues; + + try + { + defaultValues = propInfo.GetCustomAttributes(typeof(PropertyDefaultValueAttribute), false); + } + catch (ArgumentException ex) + { + throw new ArgumentException( + "The default value for the " + + propInfo.Name + + " property could not be set. Check inner exception for more information.", + ex); + } + + // 'Values' property should not have a default value as it is + // the singleton instance. + if (!propInfo.Name.Equals(AppSettings.SingletonInstancePropertyName)) + { + if (defaultValues.Length > 0) + { + var defaultValueAttribute = defaultValues[0] as PropertyDefaultValueAttribute; + + if (defaultValueAttribute != null) + { + try + { + propInfo.SetValue(this, defaultValueAttribute.Value, null); + } + catch (Exception ex) + { + throw new ArgumentException( + "The default value for the " + + propInfo.Name + + " property could not be set. Check inner exception for more information.", + ex); + } + } + } + + // Save the current value as default value. + // Properies with 'LoadDefaultsIgnore' attribute will be ignored. + if (loadDefaultsIgnore.Length <= 0) + { + this.defaults.Add(new PropertyValue( + propInfo.PropertyType, propInfo.Name, propInfo.GetValue(this, null))); + } + } + } + + serializer = new XmlSerializer(typeof(AppSettings)); + } + + #endregion + + #region Public Static Methods + + public static void LoadDefaults() + { + PropertyInfo[] propInfos = Values.GetType().GetProperties(); + + // Assign default values to the corresponding properties. + foreach (PropertyInfo propInfo in propInfos) + { + if (!propInfo.Name.Equals(AppSettings.SingletonInstancePropertyName)) + { + // Assign defaults only to non static properties + MethodInfo methodInfo = propInfo.GetGetMethod(false); + + if (methodInfo == null || methodInfo.IsStatic) + { + continue; + } + + var value = AppSettings.Values.defaults.Find(x => x.ValueName.Equals(propInfo.Name)); + + if (value != null) + { + propInfo.SetValue(Values, value.ValueData, null); + } + } + } + } + + public static void Save() + { + // Serialize this. + try + { + if (!Directory.Exists(settingsFileDir)) + { + Directory.CreateDirectory(settingsFileDir); + } + + using (FileStream fs = new FileStream( + Path.Combine(AppSettings.settingsFileDir, AppSettings.settingsFileName), + FileMode.Create)) + { + AppSettings.Values.serializer.Serialize(fs, AppSettings.Values); + } + } + catch (Exception) + { + AppSettings.OnSaveSettingsFailed(); + } + } + + public static void StoreCurrentSettings() + { + Properties.Instance.stored.Clear(); + + foreach (PropertyInfo propInfo in Values.GetType().GetProperties()) + { + // 'Values' property should not be stored as it is + // the singleton instance. + if (!propInfo.Name.Equals(AppSettings.SingletonInstancePropertyName)) + { + AppSettings.Values.stored.Add(new PropertyValue( + propInfo.PropertyType, propInfo.Name, propInfo.GetValue(Values, null))); + } + } + } + + public static void LoadLastStoredSettings() + { + PropertyInfo[] propInfos = Values.GetType().GetProperties(); + + //Gespeicherte Werte aus der Liste per Reflection den jeweiligen + //Eigenschaften der Klasse zuweisen + foreach (PropertyInfo propInfo in propInfos) + { + if (!propInfo.Name.Equals(AppSettings.SingletonInstancePropertyName)) + { + foreach (PropertyValue value in Values.stored) + { + if (propInfo.Name.Equals(value.ValueName)) + { + propInfo.SetValue(Values, value.ValueData, null); + break; + } + } + } + } + } + + public static void DeleteSettingsFile() + { + if (AppSettings.SettingsFileExists) + { + File.Delete(Path.Combine(AppSettings.settingsFileDir, AppSettings.settingsFileName)); + } + + if (Directory.Exists(AppSettings.settingsFileDir)) + { + Directory.Delete(AppSettings.settingsFileDir, true); + } + } + + public static void Reload() + { + Properties.Reload(); + } + + #endregion + + #region Private Static Methods + + private static string GetDefaultSettingsFileDirPath() + { + string path = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), + GetProductName()); + + foreach (char c in Path.GetInvalidPathChars()) + { + path = path.Replace(c, '_'); + } + + return path; + } + + private static string GetDefaultSettingsFileName() + { + string name = GetProductName() + AppSettings.SettingsFileExtension; + + foreach (char c in Path.GetInvalidFileNameChars()) + { + name = name.Replace(c, '_'); + } + + return name; + } + + private static string GetProductName() + { + var attribute = (AssemblyProductAttribute)AssemblyProductAttribute + .GetCustomAttribute(Assembly.GetExecutingAssembly(), typeof(AssemblyProductAttribute)); + + return attribute.Product; + } + + private static void OnLoadSettingsFailed() + { + if (AppSettings.LoadSettingsFailed != null) + { + AppSettings.LoadSettingsFailed(null, EventArgs.Empty); + } + } + + private static void OnSaveSettingsFailed() + { + if (AppSettings.SaveSettingsFailed != null) + { + AppSettings.SaveSettingsFailed(null, EventArgs.Empty); + } + } + + #endregion + + #endregion + } +} \ No newline at end of file diff --git a/NbfcServiceClient/AutorunEntry.cs b/NbfcServiceClient/AutorunEntry.cs new file mode 100644 index 00000000..6f24bbe2 --- /dev/null +++ b/NbfcServiceClient/AutorunEntry.cs @@ -0,0 +1,192 @@ +using Microsoft.Win32; +using System; +using System.Linq; +using System.Reflection; + +namespace StagWare.Windows +{ + public class AutorunEntry + { + #region Private Fields + + private const string RegistryAutorunPath = @"Software\Microsoft\Windows\CurrentVersion\Run"; + + private string valueName; + private string parameters; + private string applicationPath; + private bool appliesToAllUsers; + + #endregion + + #region Properties + + public string ValueName + { + get + { + return valueName; + } + + set + { + if (!value.Equals(valueName)) + { + if (Exists) + { + UpdateValueName(value); + } + + valueName = value; + } + } + } + + public string Parameters + { + get + { + return parameters; + } + + set + { + if (!value.Equals(parameters)) + { + parameters = value; + + if (Exists) + { + UpdateValue(); + } + } + } + } + + public string ApplicationPath + { + get + { + return applicationPath; + } + + set + { + if (!value.Equals(applicationPath)) + { + applicationPath = value; + + if (Exists) + { + UpdateValue(); + } + } + } + } + + public bool Exists + { + get + { + bool exists = false; + RegistryKey key = AppliesToAllUsers ? Registry.LocalMachine : Registry.CurrentUser; + + using (key = key.OpenSubKey(RegistryAutorunPath)) + { + if (key.GetValueNames().Contains(ValueName) + && key.GetValue(ValueName).Equals(string.Format("\"{0}\" {1}", ApplicationPath, Parameters))) + { + exists = true; + } + } + + return exists; + } + + set + { + if (Exists != value) + { + if (value) + { + UpdateValue(); + } + else + { + DeleteValue(); + } + } + } + } + + public bool AppliesToAllUsers + { + get + { + return appliesToAllUsers; + } + + set + { + if (appliesToAllUsers != value) + { + if (Exists) + { + DeleteValue(); + } + + appliesToAllUsers = value; + UpdateValue(); + } + } + } + + #endregion + + #region Constructor + + public AutorunEntry(string valueName, bool appliesToAllUsers = false) + { + ValueName = valueName; + Parameters = string.Empty; + ApplicationPath = Assembly.GetExecutingAssembly().Location; + AppliesToAllUsers = false; + } + + #endregion + + #region Private Methods + + private void UpdateValue() + { + RegistryKey key = AppliesToAllUsers ? Registry.LocalMachine : Registry.CurrentUser; + + using (key = key.OpenSubKey(RegistryAutorunPath, true)) + { + key.SetValue(ValueName, string.Format("\"{0}\" {1}", ApplicationPath, Parameters)); + } + } + + private void UpdateValueName(string newName) + { + RegistryKey key = AppliesToAllUsers ? Registry.LocalMachine : Registry.CurrentUser; + + using (key = key.OpenSubKey(RegistryAutorunPath, true)) + { + key.DeleteValue(ValueName); + key.SetValue(newName, string.Format("\"{0}\" {1}", ApplicationPath, Parameters)); + } + } + + private void DeleteValue() + { + RegistryKey key = AppliesToAllUsers ? Registry.LocalMachine : Registry.CurrentUser; + + using (key = key.OpenSubKey(RegistryAutorunPath, true)) + { + key.DeleteValue(ValueName); + } + } + + #endregion + } +} diff --git a/NbfcServiceClient/DesignData/FanControllerCollection.xaml b/NbfcServiceClient/DesignData/FanControllerCollection.xaml new file mode 100644 index 00000000..b9d4bf4a --- /dev/null +++ b/NbfcServiceClient/DesignData/FanControllerCollection.xaml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/NbfcServiceClient/DesignData/FanControllerViewModelCollection.cs b/NbfcServiceClient/DesignData/FanControllerViewModelCollection.cs new file mode 100644 index 00000000..c7ab5171 --- /dev/null +++ b/NbfcServiceClient/DesignData/FanControllerViewModelCollection.cs @@ -0,0 +1,18 @@ +using NbfcServiceClient.ViewModels; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Windows.Markup; + +namespace NbfcServiceClient.DesignData +{ + public class FanControllerViewModelCollection : ObservableCollection + { + public FanControllerViewModelCollection() + : base() + { + } + } +} diff --git a/NbfcServiceClient/DesignData/FanControllerViewModelData.xaml b/NbfcServiceClient/DesignData/FanControllerViewModelData.xaml new file mode 100644 index 00000000..9cbe95ed --- /dev/null +++ b/NbfcServiceClient/DesignData/FanControllerViewModelData.xaml @@ -0,0 +1,4 @@ + + diff --git a/NbfcServiceClient/DesignData/MainWindowViewModelData.xaml b/NbfcServiceClient/DesignData/MainWindowViewModelData.xaml new file mode 100644 index 00000000..85cb66c6 --- /dev/null +++ b/NbfcServiceClient/DesignData/MainWindowViewModelData.xaml @@ -0,0 +1,5 @@ + + diff --git a/NbfcServiceClient/FanControlClient.cs b/NbfcServiceClient/FanControlClient.cs new file mode 100644 index 00000000..dc89b52b --- /dev/null +++ b/NbfcServiceClient/FanControlClient.cs @@ -0,0 +1,298 @@ +using NbfcServiceClient.ViewModels; +using System; +using System.ServiceModel; +using System.Windows.Threading; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using NbfcServiceClient.NbfcService; + +namespace NbfcServiceClient +{ + public class FanControlClient : IDisposable + { + #region Private Fields + + private MainWindowViewModel viewModel; + private FanControlServiceClient client; + private DispatcherTimer timer; + + #endregion + + #region Properties + + public int UpdateInterval + { + get + { + return this.timer.Interval.Seconds; + } + + set + { + int updateInterval = value > 0 ? value : 1; + timer.Interval = new TimeSpan(0, 0, updateInterval); + } + } + + public MainWindowViewModel ViewModel + { + get + { + return viewModel; + } + } + + #endregion + + #region Constructors + + public FanControlClient(MainWindowViewModel viewModel, int updateInterval) + { + this.viewModel = viewModel; + + InitializeClient(); + + timer = new DispatcherTimer(); + timer.Tick += timer_Tick; + this.UpdateInterval = updateInterval; + + timer.Start(); + } + + #endregion + + #region Public Methods + + public void SetFanSpeed(double speed, int fanIndex) + { + try + { + this.client.SetTargetFanSpeed(speed, fanIndex); + UpdateMainViewModel(); + } + catch + { + InitializeClient(); + } + } + + public void RestartFanControl() + { + try + { + client.Restart(); + ResetMainViewModel(); + UpdateMainViewModel(); + } + catch + { + InitializeClient(); + } + } + + public void StartFanControl() + { + try + { + client.Start(); + ResetMainViewModel(); + UpdateMainViewModel(); + } + catch + { + InitializeClient(); + } + } + + public void StopFanControl() + { + try + { + client.Stop(); + ResetMainViewModel(); + UpdateMainViewModel(); + } + catch + { + InitializeClient(); + } + } + + public void SetConfig(string uniqueConfigId) + { + try + { + client.SetConfig(uniqueConfigId); + ResetMainViewModel(); + UpdateMainViewModel(); + } + catch + { + InitializeClient(); + } + } + + public void UpdateViewModel() + { + UpdateMainViewModel(); + } + + #endregion + + #region Private Methods + + private void InitializeClient() + { + try + { + if (client == null + || client.State == CommunicationState.Closed + || client.State == CommunicationState.Closing + || client.State == CommunicationState.Faulted) + { + client = new FanControlServiceClient(); + } + + if (client.State != CommunicationState.Opened + || client.State != CommunicationState.Opening) + { + client.Open(); + } + } + catch + { + } + } + + private void UpdateMainViewModel() + { + try + { + FanControlInfo info = client.GetFanControlInfo(); + + if (info != null) + { + viewModel.CpuTemperature = info.CpuTemperature; + viewModel.IsServiceAvailable = info.IsInitialized; + viewModel.SelectedConfig = info.SelectedConfig; + + if (info.FanStatus != null) + { + UpdateFanControllerViewModels(info.FanStatus); + } + } + } + catch + { + ResetMainViewModel(); + InitializeClient(); + } + } + + private void ResetMainViewModel() + { + viewModel.CpuTemperature = 0; + viewModel.IsServiceAvailable = false; + viewModel.SelectedConfig = string.Empty; + viewModel.FanControllers.Clear(); + } + + private void UpdateFanControllerViewModels(FanStatus[] status) + { + for (int i = 0; i < status.Length; i++) + { + FanStatus fs = status[i]; + + if (i >= viewModel.FanControllers.Count) + { + FanControllerViewModel vm = new FanControllerViewModel(this, i) + { + CurrentFanSpeed = fs.CurrentFanSpeed, + TargetFanSpeed = fs.TargetFanSpeed, + FanDisplayName = fs.FanDisplayName, + FanSpeedSteps = fs.FanSpeedSteps, + IsAutoFanControlEnabled = fs.AutoControlEnabled, + IsCriticalModeEnabled = fs.CriticalModeEnabled + }; + + if (fs.AutoControlEnabled) + { + vm.FanSpeedSliderValue = fs.FanSpeedSteps; + } + else + { + vm.FanSpeedSliderValue = (int)Math.Round((fs.TargetFanSpeed / 100.0) * fs.FanSpeedSteps); + } + + viewModel.FanControllers.Add(vm); + } + else + { + FanControllerViewModel vm = viewModel.FanControllers[i]; + + vm.CurrentFanSpeed = fs.CurrentFanSpeed; + vm.TargetFanSpeed = fs.TargetFanSpeed; + vm.FanDisplayName = fs.FanDisplayName; + vm.FanSpeedSteps = fs.FanSpeedSteps; + vm.IsAutoFanControlEnabled = fs.AutoControlEnabled; + vm.IsCriticalModeEnabled = fs.CriticalModeEnabled; + } + } + } + + #endregion + + #region EventHandlers + + void timer_Tick(object sender, EventArgs e) + { + UpdateMainViewModel(); + } + + #endregion + + #region IDisposable implementation + + private bool disposed; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool disposeManagedResources) + { + if (!disposed) + { + if (disposeManagedResources) + { + if (client != null) + { + try + { + client.Close(); + } + catch + { + } + + this.client = null; + } + } + + // TODO: Dispose unmanaged resources. + + disposed = true; + } + } + + ~FanControlClient() + { + Dispose(false); + } + + #endregion + } +} diff --git a/NbfcServiceClient/NbfcServiceClient.csproj b/NbfcServiceClient/NbfcServiceClient.csproj new file mode 100644 index 00000000..a80a87ac --- /dev/null +++ b/NbfcServiceClient/NbfcServiceClient.csproj @@ -0,0 +1,254 @@ + + + + + Debug + AnyCPU + {DF818D02-6FBC-44E1-88FA-0D62BD73CA95} + WinExe + Properties + NbfcServiceClient + NoteBook FanControl + v4.0 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + Client + false + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + NbfcServiceClient.App + + + nbfc.ico + + + + app.manifest + + + + ..\packages\Hardcodet.Wpf.TaskbarNotification.1.0.4.0\lib\net40\Hardcodet.Wpf.TaskbarNotification.dll + + + + + + + + + + + + + + 4.0 + + + + + + + + MSBuild:Compile + Designer + + + + + + + FanController.xaml + + + Designer + + + Designer + + + Designer + + + ToolTipFanInfo.xaml + + + TrayToolTip.xaml + + + + + + + SelectConfigWindow.xaml + + + True + True + Reference.svcmap + + + + SettingsWindow.xaml + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + MainWindow.xaml + Code + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + Reference.svcmap + + + + Designer + + + Designer + + + Designer + + + + + WCF Proxy Generator + Reference.cs + + + + + + + + + + + + + {eb60ffbc-51f9-42f7-b22b-2200c3f0cb64} + StagWare.FanControl.Configurations + + + + + + + + False + Microsoft .NET Framework 4 Client Profile %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + false + + + False + Windows Installer 4.5 + true + + + + + \ No newline at end of file diff --git a/NbfcServiceClient/Properties/AssemblyInfo.cs b/NbfcServiceClient/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..4763e776 --- /dev/null +++ b/NbfcServiceClient/Properties/AssemblyInfo.cs @@ -0,0 +1,54 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("NoteBook FanControl Client")] +[assembly: AssemblyDescription("Client for the NoteBook FanControl service.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Stefan Hirschmann - StagWare")] +[assembly: AssemblyProduct("NoteBook FanControl")] +[assembly: AssemblyCopyright("Copyright © 2013 Stefan Hirschmann")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +//In order to begin building localizable applications, set +//CultureYouAreCodingWith in your .csproj file +//inside a . For example, if you are using US english +//in your source files, set the to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: NeutralResourcesLanguageAttribute("en")] diff --git a/NbfcServiceClient/Properties/Resources.Designer.cs b/NbfcServiceClient/Properties/Resources.Designer.cs new file mode 100644 index 00000000..ea49382f --- /dev/null +++ b/NbfcServiceClient/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.18051 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace NbfcServiceClient.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("NbfcServiceClient.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/NbfcServiceClient/Properties/Resources.resx b/NbfcServiceClient/Properties/Resources.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/NbfcServiceClient/Properties/Resources.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/NbfcServiceClient/Properties/Settings.Designer.cs b/NbfcServiceClient/Properties/Settings.Designer.cs new file mode 100644 index 00000000..524ed6cf --- /dev/null +++ b/NbfcServiceClient/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.18051 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace NbfcServiceClient.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/NbfcServiceClient/Properties/Settings.settings b/NbfcServiceClient/Properties/Settings.settings new file mode 100644 index 00000000..033d7a5e --- /dev/null +++ b/NbfcServiceClient/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/NbfcServiceClient/Service References/NbfcService/NbfcServiceClient.NbfcService.FanControlInfo.datasource b/NbfcServiceClient/Service References/NbfcService/NbfcServiceClient.NbfcService.FanControlInfo.datasource new file mode 100644 index 00000000..f3b4e847 --- /dev/null +++ b/NbfcServiceClient/Service References/NbfcService/NbfcServiceClient.NbfcService.FanControlInfo.datasource @@ -0,0 +1,10 @@ + + + + NbfcServiceClient.NbfcService.FanControlInfo, Service References.NbfcService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/NbfcServiceClient/Service References/NbfcService/Reference.cs b/NbfcServiceClient/Service References/NbfcService/Reference.cs new file mode 100644 index 00000000..01f94305 --- /dev/null +++ b/NbfcServiceClient/Service References/NbfcService/Reference.cs @@ -0,0 +1,308 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.18051 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace NbfcServiceClient.NbfcService { + using System.Runtime.Serialization; + using System; + + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")] + [System.Runtime.Serialization.DataContractAttribute(Name="FanControlInfo", Namespace="http://schemas.datacontract.org/2004/07/StagWare.FanControl.Service")] + [System.SerializableAttribute()] + public partial class FanControlInfo : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged { + + [System.NonSerializedAttribute()] + private System.Runtime.Serialization.ExtensionDataObject extensionDataField; + + [System.Runtime.Serialization.OptionalFieldAttribute()] + private int CpuTemperatureField; + + [System.Runtime.Serialization.OptionalFieldAttribute()] + private NbfcServiceClient.NbfcService.FanStatus[] FanStatusField; + + [System.Runtime.Serialization.OptionalFieldAttribute()] + private bool IsInitializedField; + + [System.Runtime.Serialization.OptionalFieldAttribute()] + private string SelectedConfigField; + + [global::System.ComponentModel.BrowsableAttribute(false)] + public System.Runtime.Serialization.ExtensionDataObject ExtensionData { + get { + return this.extensionDataField; + } + set { + this.extensionDataField = value; + } + } + + [System.Runtime.Serialization.DataMemberAttribute()] + public int CpuTemperature { + get { + return this.CpuTemperatureField; + } + set { + if ((this.CpuTemperatureField.Equals(value) != true)) { + this.CpuTemperatureField = value; + this.RaisePropertyChanged("CpuTemperature"); + } + } + } + + [System.Runtime.Serialization.DataMemberAttribute()] + public NbfcServiceClient.NbfcService.FanStatus[] FanStatus { + get { + return this.FanStatusField; + } + set { + if ((object.ReferenceEquals(this.FanStatusField, value) != true)) { + this.FanStatusField = value; + this.RaisePropertyChanged("FanStatus"); + } + } + } + + [System.Runtime.Serialization.DataMemberAttribute()] + public bool IsInitialized { + get { + return this.IsInitializedField; + } + set { + if ((this.IsInitializedField.Equals(value) != true)) { + this.IsInitializedField = value; + this.RaisePropertyChanged("IsInitialized"); + } + } + } + + [System.Runtime.Serialization.DataMemberAttribute()] + public string SelectedConfig { + get { + return this.SelectedConfigField; + } + set { + if ((object.ReferenceEquals(this.SelectedConfigField, value) != true)) { + this.SelectedConfigField = value; + this.RaisePropertyChanged("SelectedConfig"); + } + } + } + + public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; + + protected void RaisePropertyChanged(string propertyName) { + System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged; + if ((propertyChanged != null)) { + propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); + } + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")] + [System.Runtime.Serialization.DataContractAttribute(Name="FanStatus", Namespace="http://schemas.datacontract.org/2004/07/StagWare.FanControl.Service")] + [System.SerializableAttribute()] + public partial class FanStatus : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged { + + [System.NonSerializedAttribute()] + private System.Runtime.Serialization.ExtensionDataObject extensionDataField; + + [System.Runtime.Serialization.OptionalFieldAttribute()] + private bool AutoControlEnabledField; + + [System.Runtime.Serialization.OptionalFieldAttribute()] + private bool CriticalModeEnabledField; + + [System.Runtime.Serialization.OptionalFieldAttribute()] + private double CurrentFanSpeedField; + + [System.Runtime.Serialization.OptionalFieldAttribute()] + private string FanDisplayNameField; + + [System.Runtime.Serialization.OptionalFieldAttribute()] + private int FanSpeedStepsField; + + [System.Runtime.Serialization.OptionalFieldAttribute()] + private double TargetFanSpeedField; + + [global::System.ComponentModel.BrowsableAttribute(false)] + public System.Runtime.Serialization.ExtensionDataObject ExtensionData { + get { + return this.extensionDataField; + } + set { + this.extensionDataField = value; + } + } + + [System.Runtime.Serialization.DataMemberAttribute()] + public bool AutoControlEnabled { + get { + return this.AutoControlEnabledField; + } + set { + if ((this.AutoControlEnabledField.Equals(value) != true)) { + this.AutoControlEnabledField = value; + this.RaisePropertyChanged("AutoControlEnabled"); + } + } + } + + [System.Runtime.Serialization.DataMemberAttribute()] + public bool CriticalModeEnabled { + get { + return this.CriticalModeEnabledField; + } + set { + if ((this.CriticalModeEnabledField.Equals(value) != true)) { + this.CriticalModeEnabledField = value; + this.RaisePropertyChanged("CriticalModeEnabled"); + } + } + } + + [System.Runtime.Serialization.DataMemberAttribute()] + public double CurrentFanSpeed { + get { + return this.CurrentFanSpeedField; + } + set { + if ((this.CurrentFanSpeedField.Equals(value) != true)) { + this.CurrentFanSpeedField = value; + this.RaisePropertyChanged("CurrentFanSpeed"); + } + } + } + + [System.Runtime.Serialization.DataMemberAttribute()] + public string FanDisplayName { + get { + return this.FanDisplayNameField; + } + set { + if ((object.ReferenceEquals(this.FanDisplayNameField, value) != true)) { + this.FanDisplayNameField = value; + this.RaisePropertyChanged("FanDisplayName"); + } + } + } + + [System.Runtime.Serialization.DataMemberAttribute()] + public int FanSpeedSteps { + get { + return this.FanSpeedStepsField; + } + set { + if ((this.FanSpeedStepsField.Equals(value) != true)) { + this.FanSpeedStepsField = value; + this.RaisePropertyChanged("FanSpeedSteps"); + } + } + } + + [System.Runtime.Serialization.DataMemberAttribute()] + public double TargetFanSpeed { + get { + return this.TargetFanSpeedField; + } + set { + if ((this.TargetFanSpeedField.Equals(value) != true)) { + this.TargetFanSpeedField = value; + this.RaisePropertyChanged("TargetFanSpeed"); + } + } + } + + public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; + + protected void RaisePropertyChanged(string propertyName) { + System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged; + if ((propertyChanged != null)) { + propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); + } + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ServiceModel.ServiceContractAttribute(ConfigurationName="NbfcService.IFanControlService")] + public interface IFanControlService { + + [System.ServiceModel.OperationContractAttribute(IsOneWay=true, Action="http://tempuri.org/IFanControlService/SetTargetFanSpeed")] + void SetTargetFanSpeed(double value, int fanIndex); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IFanControlService/GetFanControlInfo", ReplyAction="http://tempuri.org/IFanControlService/GetFanControlInfoResponse")] + NbfcServiceClient.NbfcService.FanControlInfo GetFanControlInfo(); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IFanControlService/Restart", ReplyAction="http://tempuri.org/IFanControlService/RestartResponse")] + bool Restart(); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IFanControlService/Start", ReplyAction="http://tempuri.org/IFanControlService/StartResponse")] + bool Start(); + + [System.ServiceModel.OperationContractAttribute(IsOneWay=true, Action="http://tempuri.org/IFanControlService/Stop")] + void Stop(); + + [System.ServiceModel.OperationContractAttribute(IsOneWay=true, Action="http://tempuri.org/IFanControlService/SetConfig")] + void SetConfig(string uniqueConfigId); + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + public interface IFanControlServiceChannel : NbfcServiceClient.NbfcService.IFanControlService, System.ServiceModel.IClientChannel { + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + public partial class FanControlServiceClient : System.ServiceModel.ClientBase, NbfcServiceClient.NbfcService.IFanControlService { + + public FanControlServiceClient() { + } + + public FanControlServiceClient(string endpointConfigurationName) : + base(endpointConfigurationName) { + } + + public FanControlServiceClient(string endpointConfigurationName, string remoteAddress) : + base(endpointConfigurationName, remoteAddress) { + } + + public FanControlServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : + base(endpointConfigurationName, remoteAddress) { + } + + public FanControlServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : + base(binding, remoteAddress) { + } + + public void SetTargetFanSpeed(double value, int fanIndex) { + base.Channel.SetTargetFanSpeed(value, fanIndex); + } + + public NbfcServiceClient.NbfcService.FanControlInfo GetFanControlInfo() { + return base.Channel.GetFanControlInfo(); + } + + public bool Restart() { + return base.Channel.Restart(); + } + + public bool Start() { + return base.Channel.Start(); + } + + public void Stop() { + base.Channel.Stop(); + } + + public void SetConfig(string uniqueConfigId) { + base.Channel.SetConfig(uniqueConfigId); + } + } +} diff --git a/NbfcServiceClient/Service References/NbfcService/Reference.svcmap b/NbfcServiceClient/Service References/NbfcService/Reference.svcmap new file mode 100644 index 00000000..8ece79e3 --- /dev/null +++ b/NbfcServiceClient/Service References/NbfcService/Reference.svcmap @@ -0,0 +1,33 @@ + + + + false + true + + false + false + false + + + true + Auto + true + true + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NbfcServiceClient/Service References/NbfcService/StagWare.FanControl.Service.xsd b/NbfcServiceClient/Service References/NbfcService/StagWare.FanControl.Service.xsd new file mode 100644 index 00000000..f39bdc01 --- /dev/null +++ b/NbfcServiceClient/Service References/NbfcService/StagWare.FanControl.Service.xsd @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NbfcServiceClient/Service References/NbfcService/configuration.svcinfo b/NbfcServiceClient/Service References/NbfcService/configuration.svcinfo new file mode 100644 index 00000000..a81e6145 --- /dev/null +++ b/NbfcServiceClient/Service References/NbfcService/configuration.svcinfo @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/NbfcServiceClient/Service References/NbfcService/configuration91.svcinfo b/NbfcServiceClient/Service References/NbfcService/configuration91.svcinfo new file mode 100644 index 00000000..c1a03395 --- /dev/null +++ b/NbfcServiceClient/Service References/NbfcService/configuration91.svcinfo @@ -0,0 +1,165 @@ + + + + + + + NetNamedPipeBinding_IFanControlService + + + + + + + + + + + + + + + False + + + Buffered + + + OleTransactions + + + StrongWildcard + + + + + + 65536 + + + 0 + + + + + + System.ServiceModel.Configuration.XmlDictionaryReaderQuotasElement + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + System.ServiceModel.Configuration.NetNamedPipeSecurityElement + + + Transport + + + System.ServiceModel.Configuration.NamedPipeTransportSecurityElement + + + EncryptAndSign + + + + + + + + + net.pipe://localhost/StagWare.FanControl.Service/FanControlService + + + + + + netNamedPipeBinding + + + NetNamedPipeBinding_IFanControlService + + + NbfcService.IFanControlService + + + System.ServiceModel.Configuration.AddressHeaderCollectionElement + + + <Header /> + + + System.ServiceModel.Configuration.IdentityElement + + + System.ServiceModel.Configuration.UserPrincipalNameElement + + + + + + System.ServiceModel.Configuration.ServicePrincipalNameElement + + + + + + System.ServiceModel.Configuration.DnsElement + + + localhost + + + System.ServiceModel.Configuration.RsaElement + + + + + + System.ServiceModel.Configuration.CertificateElement + + + + + + System.ServiceModel.Configuration.CertificateReferenceElement + + + My + + + LocalMachine + + + FindBySubjectDistinguishedName + + + + + + False + + + NetNamedPipeBinding_IFanControlService + + + + + + + + + + + \ No newline at end of file diff --git a/NbfcServiceClient/Service References/NbfcService/service.wsdl b/NbfcServiceClient/Service References/NbfcService/service.wsdl new file mode 100644 index 00000000..5ffd5e48 --- /dev/null +++ b/NbfcServiceClient/Service References/NbfcService/service.wsdl @@ -0,0 +1,149 @@ + + + + + + + + + + + + EncryptAndSign + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + net.pipe://localhost/StagWare.FanControl.Service/FanControlService + + localhost + + + + + \ No newline at end of file diff --git a/NbfcServiceClient/Service References/NbfcService/service.xsd b/NbfcServiceClient/Service References/NbfcService/service.xsd new file mode 100644 index 00000000..bd5920eb --- /dev/null +++ b/NbfcServiceClient/Service References/NbfcService/service.xsd @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NbfcServiceClient/Service References/NbfcService/service1.xsd b/NbfcServiceClient/Service References/NbfcService/service1.xsd new file mode 100644 index 00000000..b4d5ff0f --- /dev/null +++ b/NbfcServiceClient/Service References/NbfcService/service1.xsd @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NbfcServiceClient/UserControls/FanController.xaml b/NbfcServiceClient/UserControls/FanController.xaml new file mode 100644 index 00000000..a30b1ddd --- /dev/null +++ b/NbfcServiceClient/UserControls/FanController.xaml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + diff --git a/NbfcServiceClient/UserControls/FanController.xaml.cs b/NbfcServiceClient/UserControls/FanController.xaml.cs new file mode 100644 index 00000000..6a1fedfe --- /dev/null +++ b/NbfcServiceClient/UserControls/FanController.xaml.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace NbfcServiceClient.UserControls +{ + /// + /// Interaction logic for FanController.xaml + /// + public partial class FanController : UserControl + { + public FanController() + { + InitializeComponent(); + } + } +} diff --git a/NbfcServiceClient/UserControls/ToolTipFanInfo.xaml b/NbfcServiceClient/UserControls/ToolTipFanInfo.xaml new file mode 100644 index 00000000..5303fe1d --- /dev/null +++ b/NbfcServiceClient/UserControls/ToolTipFanInfo.xaml @@ -0,0 +1,29 @@ + + + + + + + + diff --git a/NbfcServiceClient/UserControls/ToolTipFanInfo.xaml.cs b/NbfcServiceClient/UserControls/ToolTipFanInfo.xaml.cs new file mode 100644 index 00000000..020a47c9 --- /dev/null +++ b/NbfcServiceClient/UserControls/ToolTipFanInfo.xaml.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace NbfcServiceClient.UserControls +{ + /// + /// Interaction logic for ToolTipFanInfo.xaml + /// + public partial class ToolTipFanInfo : UserControl + { + public ToolTipFanInfo() + { + InitializeComponent(); + } + } +} diff --git a/NbfcServiceClient/UserControls/TrayToolTip.xaml b/NbfcServiceClient/UserControls/TrayToolTip.xaml new file mode 100644 index 00000000..e3b0dec2 --- /dev/null +++ b/NbfcServiceClient/UserControls/TrayToolTip.xaml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/NbfcServiceClient/UserControls/TrayToolTip.xaml.cs b/NbfcServiceClient/UserControls/TrayToolTip.xaml.cs new file mode 100644 index 00000000..f0dfe445 --- /dev/null +++ b/NbfcServiceClient/UserControls/TrayToolTip.xaml.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace NbfcServiceClient.UserControls +{ + /// + /// Interaction logic for TrayToolTip.xaml + /// + public partial class TrayToolTip : UserControl + { + public TrayToolTip() + { + InitializeComponent(); + } + } +} diff --git a/NbfcServiceClient/ValueConverters/FanDisplayNameToTextConverter.cs b/NbfcServiceClient/ValueConverters/FanDisplayNameToTextConverter.cs new file mode 100644 index 00000000..ca8407a2 --- /dev/null +++ b/NbfcServiceClient/ValueConverters/FanDisplayNameToTextConverter.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows.Data; + +namespace NbfcServiceClient.ValueConverters +{ + [ValueConversion(typeof(string), typeof(string))] + public class FanDisplayNameToTextConverter : IMultiValueConverter + { + private const string StringFormat = "Fan #{0}"; + + public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + string s = (string)values[0]; + + if (string.IsNullOrWhiteSpace(s)) + { + return string.Format(StringFormat, (int)values[1] + 1); + } + else + { + return s; + } + } + + public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/NbfcServiceClient/ValueConverters/FanSpeedSliderValueToTextConverter.cs b/NbfcServiceClient/ValueConverters/FanSpeedSliderValueToTextConverter.cs new file mode 100644 index 00000000..5b2a1e39 --- /dev/null +++ b/NbfcServiceClient/ValueConverters/FanSpeedSliderValueToTextConverter.cs @@ -0,0 +1,49 @@ +using System; +using System.Windows.Data; + +namespace NbfcServiceClient.ValueConverters +{ + [ValueConversion(typeof(double), typeof(string))] + public class FanSpeedSliderValueToTextConverter : IMultiValueConverter + { + #region Constants + + private const string StringFormat = "{0:0.0}%"; + private const string AutoControlledText = "Auto"; + private const double AutoControlledSpeed = 101; + + #endregion + + #region IMultiValueConverter implementation + + public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + int steps = (int)values[1]; + + if (steps == 1) + { + return string.Format(StringFormat, 0); + } + else + { + double speed = ((double)values[0] / (steps - 1)) * 100; + + if (speed >= 0 && speed <= 100) + { + return string.Format(StringFormat, speed); + } + else + { + return AutoControlledText; + } + } + } + + public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) + { + throw new NotImplementedException(); + } + + #endregion + } +} diff --git a/NbfcServiceClient/ValueConverters/TargetFanSpeedToTextConverter.cs b/NbfcServiceClient/ValueConverters/TargetFanSpeedToTextConverter.cs new file mode 100644 index 00000000..29cd27a8 --- /dev/null +++ b/NbfcServiceClient/ValueConverters/TargetFanSpeedToTextConverter.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows.Data; + +namespace NbfcServiceClient.ValueConverters +{ + [ValueConversion(typeof(double), typeof(string))] + public class TargetFanSpeedToTextConverter : IMultiValueConverter + { + #region Constants + + private const string StringFormat = "{0:0.0}%"; + private const string AutoControledSuffix = " (Auto)"; + private const string CriticalModeSuffix = " (Critical)"; + + #endregion + + #region IMultiValueConverter implementation + + public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + string text = string.Format(StringFormat, (double)values[0]); + + if ((bool)values[2]) + { + text += CriticalModeSuffix; + } + else if ((bool)values[1]) + { + text += AutoControledSuffix; + } + + return text; + } + + public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) + { + throw new NotImplementedException(); + } + + #endregion + } +} diff --git a/NbfcServiceClient/ViewModels/FanControllerViewModel.cs b/NbfcServiceClient/ViewModels/FanControllerViewModel.cs new file mode 100644 index 00000000..32350d27 --- /dev/null +++ b/NbfcServiceClient/ViewModels/FanControllerViewModel.cs @@ -0,0 +1,229 @@ +using NbfcServiceClient.NbfcService; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Windows.Threading; + +namespace NbfcServiceClient.ViewModels +{ + public class FanControllerViewModel : ViewModelBase + { + #region Constants + + private const int SetFanSpeedDelay = 500; // milliseconds + + #endregion + + #region Private Fields + + private double currentFanSpeed; + private double targetFanSpeed; + private double fanSpeedSliderValue; + private int fanSpeedSteps; + private bool isAutoFanControlEnabled; + private string fanDisplayName; + private bool isCriticalModeEnabled; + + private FanControlClient client; + private int fanIndex; + private DispatcherTimer timer; + + #endregion + + #region Constructors + + public FanControllerViewModel() + { + this.timer = new DispatcherTimer(); + this.timer.Interval = TimeSpan.FromMilliseconds(SetFanSpeedDelay); + + timer.Tick += timer_Tick; + } + + public FanControllerViewModel(FanControlClient client, int fanIndex) + : this() + { + this.client = client; + this.fanIndex = fanIndex; + } + + #endregion + + #region Properties + + public int FanIndex + { + get + { + return fanIndex; + } + + set + { + if (fanIndex != value) + { + fanIndex = value; + OnPropertyChanged("FanIndex"); + } + } + } + + public string FanDisplayName + { + get + { + return + fanDisplayName; + } + + set + { + if (fanDisplayName != value) + { + fanDisplayName = value; + OnPropertyChanged("FanDisplayName"); + } + } + } + + public double FanSpeedSliderValue + { + get + { + return fanSpeedSliderValue; + } + + set + { + if (fanSpeedSliderValue != value) + { + fanSpeedSliderValue = value; + OnPropertyChanged("FanSpeed"); + SetSpeedDelayed(); + } + } + } + + public double TargetFanSpeed + { + get + { + return targetFanSpeed; + } + + set + { + if (targetFanSpeed != value) + { + targetFanSpeed = value; + OnPropertyChanged("TargetFanSpeed"); + } + } + } + + public double CurrentFanSpeed + { + get + { + return currentFanSpeed; + } + + set + { + if (currentFanSpeed != value) + { + currentFanSpeed = value; + OnPropertyChanged("CurrentFanSpeed"); + } + } + } + + public bool IsAutoFanControlEnabled + { + get + { + return isAutoFanControlEnabled; + } + + set + { + if (isAutoFanControlEnabled != value) + { + isAutoFanControlEnabled = value; + OnPropertyChanged("IsAutoFanControlEnabled"); + } + } + } + + public bool IsCriticalModeEnabled + { + get + { + return isCriticalModeEnabled; + } + + set + { + if (isCriticalModeEnabled != value) + { + isCriticalModeEnabled = value; + OnPropertyChanged("IsCriticalModeEnabled"); + } + } + } + + public int FanSpeedSteps + { + get + { + return fanSpeedSteps; + } + + set + { + if (fanSpeedSteps != value) + { + fanSpeedSteps = value; + OnPropertyChanged("FanSpeedSteps"); + } + } + } + + #endregion + + #region Private Methods + + private void SetSpeedDelayed() + { + this.timer.Stop(); + this.timer.Start(); + } + + private double GetFanSpeedPercentage() + { + if (this.fanSpeedSteps == 1) + { + return 0; + } + else + { + // subtract 1 from steps, because last step is reserved for "auto control" setting + return (this.fanSpeedSliderValue / (this.fanSpeedSteps - 1)) * 100; + } + } + + #endregion + + #region Event Handlers + + void timer_Tick(object sender, EventArgs e) + { + this.timer.Stop(); + this.client.SetFanSpeed(GetFanSpeedPercentage(), this.fanIndex); + } + + #endregion + } +} diff --git a/NbfcServiceClient/ViewModels/MainWindowViewModel.cs b/NbfcServiceClient/ViewModels/MainWindowViewModel.cs new file mode 100644 index 00000000..5b43fec8 --- /dev/null +++ b/NbfcServiceClient/ViewModels/MainWindowViewModel.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; + +namespace NbfcServiceClient.ViewModels +{ + public class MainWindowViewModel : ViewModelBase + { + #region Private Fields + + private bool isServiceAvailable; + private int cpuTemperature; + private string selectedConfig; + private ObservableCollection fanControllers; + + #endregion + + #region Constructors + + public MainWindowViewModel() + { + this.FanControllers = new ObservableCollection(); + } + + #endregion + + #region Properties + + public string SelectedConfig + { + get + { + return + selectedConfig; + } + + set + { + if (selectedConfig != value) + { + selectedConfig = value; + OnPropertyChanged("SelectedConfig"); + } + } + } + + public bool IsServiceAvailable + { + get + { + return + isServiceAvailable; + } + + set + { + if (isServiceAvailable != value) + { + isServiceAvailable = value; + OnPropertyChanged("IsServiceAvailable"); + } + } + } + + public int CpuTemperature + { + get + { + return cpuTemperature; + } + + set + { + if (cpuTemperature != value) + { + cpuTemperature = value; + OnPropertyChanged("CpuTemperature"); + } + } + } + + public ObservableCollection FanControllers + { + get + { + return fanControllers; + } + + set + { + if (fanControllers != value) + { + fanControllers = value; + OnPropertyChanged("FanControllers"); + } + } + } + + #endregion + + #region Private Methods + + #endregion + } +} diff --git a/NbfcServiceClient/ViewModels/ViewModelBase.cs b/NbfcServiceClient/ViewModels/ViewModelBase.cs new file mode 100644 index 00000000..2a0e373f --- /dev/null +++ b/NbfcServiceClient/ViewModels/ViewModelBase.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; + +namespace NbfcServiceClient.ViewModels +{ + public abstract class ViewModelBase : INotifyPropertyChanged + { + #region INotifyPropertyChanged implementation + + public event PropertyChangedEventHandler PropertyChanged; + + protected void OnPropertyChanged(string propertyName) + { + if (this.PropertyChanged != null) + { + PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); + } + } + + #endregion + } +} diff --git a/NbfcServiceClient/Windows/MainWindow.xaml b/NbfcServiceClient/Windows/MainWindow.xaml new file mode 100644 index 00000000..9b0abadd --- /dev/null +++ b/NbfcServiceClient/Windows/MainWindow.xaml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + If you like my work, click here to buy me a beer :) + + + + + + + + + + + + + + + + diff --git a/NbfcServiceClient/Windows/MainWindow.xaml.cs b/NbfcServiceClient/Windows/MainWindow.xaml.cs new file mode 100644 index 00000000..5569126d --- /dev/null +++ b/NbfcServiceClient/Windows/MainWindow.xaml.cs @@ -0,0 +1,368 @@ +using NbfcServiceClient.ViewModels; +using StagWare.Settings; +using System; +using System.ComponentModel; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Runtime.InteropServices; +using System.Windows; +using System.Windows.Input; +using System.Windows.Interop; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Threading; + +namespace NbfcServiceClient.Windows +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window, IDisposable + { + #region Nested Types + + private static class NativeMethods + { + [DllImport("user32.dll", SetLastError = true)] + public static extern bool DestroyIcon(IntPtr hIcon); + } + + #endregion + + #region Constants + + private const int UpdateInterval = 3; // seconds + private const int SaveWindowSizeDelay = 1; // seconds + + private const double DefaultTrayIconSize = 16.0; + private const double DefaultTrayFontSize = 16; + private const int TrayIconDPI = 72; + private const string TrayIconFontFamily = "Microsoft Sans Serif"; + private const string SettingsFileName = "NbfcSettings.xml"; + private const string SettingsDirectoryName = "NoteBook FanControl"; + private const string StartInTrayParameter = "-tray"; + private const string LoadSettingsFileParameter = "-settings:"; + + #endregion + + #region Private Fields + + private FanControlClient client; + private MainWindowViewModel viewModel; + private DispatcherTimer saveSizeTimer; + private bool close; + private double lastWidth; + private double lastHeight; + + #endregion + + #region Constructors + + public MainWindow() + { + ProcessCommandLineArgs(); + InitializeAppSettings(); + InitializeComponent(); + + this.saveSizeTimer = new DispatcherTimer(); + this.saveSizeTimer.Interval = TimeSpan.FromSeconds(SaveWindowSizeDelay); + this.saveSizeTimer.Tick += saveSizeTimer_Tick; + + this.viewModel = new MainWindowViewModel(); + viewModel.PropertyChanged += viewModel_PropertyChanged; + + this.client = new FanControlClient(viewModel, UpdateInterval); + this.DataContext = viewModel; + client.UpdateViewModel(); + + this.Height = AppSettings.Values.WindowHeight; + this.Width = AppSettings.Values.WindowWidth; + this.SizeChanged += MainWindow_SizeChanged; + } + + #region Helper Methods + + private static void InitializeAppSettings() + { + string path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + path = Path.Combine(path, SettingsDirectoryName); + + AppSettings.SettingsDirectoryPath = path; + AppSettings.SettingsFileName = SettingsFileName; + } + + private void ProcessCommandLineArgs() + { + foreach (string s in Environment.GetCommandLineArgs()) + { + if (s.Equals(StartInTrayParameter, StringComparison.OrdinalIgnoreCase)) + { + this.WindowState = System.Windows.WindowState.Minimized; + this.Visibility = System.Windows.Visibility.Hidden; + } + else if (s.StartsWith(LoadSettingsFileParameter, StringComparison.OrdinalIgnoreCase)) + { + string path = s.Substring(LoadSettingsFileParameter.Length); + + AppSettings.SettingsDirectoryPath = Path.GetDirectoryName(path); + AppSettings.SettingsFileName = Path.GetFileName(path); + } + } + } + + #endregion + + #endregion + + #region Public Methods + + public void UpdateNotifyIcon() + { + using (var bmp = RenderTrayImage(viewModel.CpuTemperature)) + { + var tmp = notifyIcon.Icon; + notifyIcon.Icon = System.Drawing.Icon.FromHandle(bmp.GetHicon()); + + if (tmp != null) + { + NativeMethods.DestroyIcon(tmp.Handle); + tmp.Dispose(); + } + } + } + + #endregion + + #region Private Methods + + private System.Drawing.Bitmap RenderTrayImage(int cpuTemperature) + { + int trayIconSize = System.Windows.Forms.SystemInformation.IconSize.Height / 2; + double scalingFactor = trayIconSize / DefaultTrayIconSize; + double fontSize = DefaultTrayFontSize * scalingFactor; + Color c = AppSettings.Values.TrayIconForegroundColor; + + FormattedText text = new FormattedText( + cpuTemperature.ToString(), + new CultureInfo("en-us"), + FlowDirection.LeftToRight, + new Typeface( + new System.Windows.Media.FontFamily(TrayIconFontFamily), + FontStyles.Normal, + FontWeights.SemiBold, + new FontStretch()), + fontSize, + new SolidColorBrush(c)); + + var drawingVisual = new DrawingVisual(); + var drawingContext = drawingVisual.RenderOpen(); + drawingContext.DrawText(text, new Point(2, 2)); + drawingContext.Close(); + + var target = new RenderTargetBitmap( + trayIconSize, + trayIconSize, + TrayIconDPI, + TrayIconDPI, + PixelFormats.Default); + + target.Clear(); + target.Render(drawingVisual); + + var enc = new PngBitmapEncoder(); + enc.Frames.Add(BitmapFrame.Create(target)); + + using (var ms = new MemoryStream()) + { + enc.Save(ms); + ms.Position = 0; + + return (System.Drawing.Bitmap)System.Drawing.Bitmap.FromStream(ms); + } + } + + private bool IsPathValid(string path) + { + bool isValid = false; + + try + { + var tmp = new FileInfo(path); + isValid = true; + } + catch + { + } + + return isValid; + } + + #endregion + + #region EventHandlers + + #region FanControl + + private void selectConfig_Click(object sender, RoutedEventArgs e) + { + var window = new SelectConfigWindow(client); + window.Owner = this; + window.ShowDialog(); + } + + private void CheckBox_Click(object sender, RoutedEventArgs e) + { + try + { + Mouse.OverrideCursor = Cursors.Wait; + + if (this.viewModel.IsServiceAvailable) + { + this.client.StartFanControl(); + } + else + { + this.client.StopFanControl(); + } + } + finally + { + Mouse.OverrideCursor = null; + } + } + + #endregion + + #region NotifyIcon + + private void window_StateChanged(object sender, EventArgs e) + { + if (this.WindowState == WindowState.Minimized) + { + this.Hide(); + } + } + + private void close_Click(object sender, RoutedEventArgs e) + { + close = true; + Close(); + } + + private void notifyIcon_TrayLeftMouseDown(object sender, RoutedEventArgs e) + { + if (this.Visibility == Visibility.Visible) + { + WindowState = WindowState.Minimized; + Hide(); + } + else + { + Show(); + Activate(); + WindowState = WindowState.Normal; + } + } + + void viewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == "CpuTemperature") + { + UpdateNotifyIcon(); + } + } + + private void Window_Closing(object sender, CancelEventArgs e) + { + if (AppSettings.Values.CloseToTray && !close) + { + e.Cancel = true; + WindowState = System.Windows.WindowState.Minimized; + } + } + + #endregion + + #region Window + + void MainWindow_SizeChanged(object sender, SizeChangedEventArgs e) + { + if (this.WindowState != WindowState.Minimized) + { + lastHeight = this.Height; + lastWidth = this.Width; + } + + saveSizeTimer.Stop(); + saveSizeTimer.Start(); + } + + void saveSizeTimer_Tick(object sender, EventArgs e) + { + this.saveSizeTimer.Stop(); + + AppSettings.Values.WindowHeight = lastHeight; + AppSettings.Values.WindowWidth = lastWidth; + AppSettings.Save(); + } + + #endregion + + #region Settings & Donation + + private void donationLink_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e) + { + Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri)); + e.Handled = true; + } + + private void settings_Click(object sender, RoutedEventArgs e) + { + var wnd = new NbfcServiceClient.Windows.SettingsWindow(); + wnd.Owner = this; + + wnd.ShowDialog(); + } + + #endregion + + #endregion + + #region IDisposable implementation + + private bool disposed; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool disposeManagedResources) + { + if (!disposed) + { + if (disposeManagedResources) + { + if (this.client != null) + { + this.client.Dispose(); + this.client = null; + } + } + + //TODO: Dispose unmanaged resources. + + disposed = true; + } + } + + ~MainWindow() + { + Dispose(false); + } + + #endregion + } +} diff --git a/NbfcServiceClient/Windows/SelectConfigWindow.xaml b/NbfcServiceClient/Windows/SelectConfigWindow.xaml new file mode 100644 index 00000000..20fc92c9 --- /dev/null +++ b/NbfcServiceClient/Windows/SelectConfigWindow.xaml @@ -0,0 +1,17 @@ + + + + +