diff --git a/GreenshotCore/Configuration/CoreConfiguration.cs b/GreenshotCore/Configuration/CoreConfiguration.cs
new file mode 100644
index 000000000..f4163ce55
--- /dev/null
+++ b/GreenshotCore/Configuration/CoreConfiguration.cs
@@ -0,0 +1,36 @@
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2010 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: http://getgreenshot.org/
+ * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+using System;
+
+namespace GreenshotCore.Configuration {
+ ///
+ /// Description of CoreConfiguration.
+ ///
+ [IniSection("Core", Description="Greenshot core configuration")]
+ public class CoreConfiguration : IniSection {
+ [IniProperty("Language", Description="The language in IETF format (e.g. en-EN)", DefaultValue="en-EN")]
+ public string Language;
+ [IniProperty("RegisterHotkeys", Description="Register the hotkeys?", DefaultValue="true")]
+ public bool RegisterHotkeys;
+ [IniProperty("IsFirstLaunch", Description="Is this the first time launch?", DefaultValue="true")]
+ public bool IsFirstLaunch;
+ }
+}
diff --git a/GreenshotCore/Core/ConfigHelper.cs b/GreenshotCore/Core/ConfigHelper.cs
new file mode 100644
index 000000000..4dd2176ce
--- /dev/null
+++ b/GreenshotCore/Core/ConfigHelper.cs
@@ -0,0 +1,391 @@
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2010 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: http://getgreenshot.org/
+ * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Windows.Forms;
+
+namespace GreenshotCore.Configuration {
+
+ ///
+ /// Attribute for telling that this class is linked to a section in the ini-configuration
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple=false)]
+ public class IniSectionAttribute : Attribute {
+ private string name;
+ public IniSectionAttribute(string name) {
+ this.name = name;
+ }
+ public string Description;
+ public string Name {
+ get {return name;}
+ set {name = value;}
+ }
+ }
+
+ ///
+ /// Attribute for telling that a field is linked to a property in the ini-configuration selection
+ ///
+ [AttributeUsage(AttributeTargets.Field, AllowMultiple=false)]
+ public class IniPropertyAttribute : Attribute {
+ private string name;
+ public IniPropertyAttribute(string name) {
+ this.name = name;
+ }
+ public string Description;
+ public string DefaultValue;
+ public string Name {
+ get {return name;}
+ set {name = value;}
+ }
+ }
+
+ // Interface for
+ public interface IniSection {
+ }
+
+ public class IniConfig {
+ private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(IniConfig));
+ private const string CONFIG_FILE_NAME = "greenshot.ini";
+ private const string DEFAULTS_CONFIG_FILE_NAME = "greenshot-defaults.ini";
+
+ private static IniConfig instance = null;
+
+ private string iniLocation = null;
+ private Dictionary sectionMap = new Dictionary();
+ private Dictionary> iniProperties = new Dictionary>();
+
+ ///
+ /// get an instance of IniConfig
+ ///
+ ///
+ public static IniConfig GetInstance() {
+ if (instance == null) {
+ instance = new IniConfig();
+ }
+ return instance;
+ }
+
+ ///
+ /// Create the location of the configuration file
+ ///
+ private static string CreateIniLocation(string configFilename) {
+ // check if file is in the same location as started from, if this is the case
+ // we will use this file instead of the Applicationdate folder
+ // Done for Feature Request #2741508
+ if (File.Exists(Path.Combine(Application.StartupPath, configFilename))) {
+ return Path.Combine(Application.StartupPath, configFilename);
+ }
+ return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),@"Greenshot\" + configFilename);
+ }
+
+ ///
+ /// Private Constuctor,
+ ///
+ ///
+ private IniConfig() {
+ this.iniLocation = CreateIniLocation(CONFIG_FILE_NAME);
+ Read(CreateIniLocation(DEFAULTS_CONFIG_FILE_NAME));
+ Read(CreateIniLocation(iniLocation));
+ }
+
+ ///
+ /// Read the ini file into the Dictionary
+ ///
+ /// Path & Filename of ini file
+ private void Read(string iniLocation) {
+ if (!File.Exists(iniLocation)) {
+ LOG.Info("Can't find file: " + iniLocation);
+ return;
+ }
+ LOG.Info("Reading ini-properties from file: " + iniLocation);
+
+ String currentSection = null;
+ foreach (string line in File.ReadAllLines(iniLocation)) {
+ if (line == null) {
+ continue;
+ }
+ string currentLine = line.TrimStart();
+ if (currentLine.StartsWith("[")) {
+ currentSection = currentLine.Substring(1, currentLine.IndexOf(']')-1);
+ LOG.Debug("Found section: " + currentSection);
+ } else if (!currentLine.StartsWith(";") && currentLine.IndexOf('=') > 0) {
+ string [] split = currentLine.Split(new Char[] {'='}, 2);
+ if (split != null && split.Length == 2) {
+ string name = split[0];
+ if (name == null || name.Length < 1) {
+ continue;
+ }
+ name = name.Trim();
+ String value = split[1];
+ if (!HasProperty(currentSection, name)) {
+ SetProperty(currentSection, name, value);
+ } else {
+ ChangeProperty(currentSection, name, value);
+ }
+ }
+ }
+ }
+ }
+
+ ///
+ /// A generic method which returns an instance of the supplied type, filled with it's configuration
+ ///
+ /// Filled instance of IniSection type which was supplied
+ public T GetSection() where T : IniSection {
+ T section;
+ Type iniSectionType = typeof(T);
+ string sectionName = getSectionName(iniSectionType);
+ if (sectionMap.ContainsKey(sectionName)) {
+ section = (T)sectionMap[sectionName];
+ } else {
+ // Create instance of this type
+ section = (T)Activator.CreateInstance(iniSectionType);
+
+ // Store for later save & retrieval
+ sectionMap.Add(sectionName, section);
+
+ // Get the properties for the section
+ Dictionary properties = null;
+ if (iniProperties.ContainsKey(sectionName)) {
+ properties = iniProperties[sectionName];
+ }
+
+ // Iterate over the fields and fill them
+ FieldInfo[] fields = iniSectionType.GetFields();
+ foreach(FieldInfo field in fields) {
+ if (Attribute.IsDefined(field, typeof(IniPropertyAttribute))) {
+ IniPropertyAttribute iniPropertyAttribute = (IniPropertyAttribute)field.GetCustomAttributes(typeof(IniPropertyAttribute), false)[0];
+ string propertyName = iniPropertyAttribute.Name;
+ string propertyValue = null;
+ // Get the value from the ini file, if there is none take the default
+ if (properties != null && properties.ContainsKey(propertyName)) {
+ propertyValue = properties[propertyName];
+ } else {
+ propertyValue = iniPropertyAttribute.DefaultValue;
+ }
+
+ // Get the type, or the underlying type for nullables
+ Type fieldType = field.FieldType;
+ if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) {
+ // We are dealing with a generic type that is nullable
+ fieldType = Nullable.GetUnderlyingType(fieldType);
+ }
+
+ // Now set the value
+ if (fieldType == typeof(string)) {
+ field.SetValue(section, propertyValue);
+ } else if (fieldType == typeof(bool) || fieldType == typeof(bool?)) {
+ field.SetValue(section, bool.Parse(propertyValue));
+ } else if (fieldType == typeof(int) || fieldType == typeof(int?)) {
+ field.SetValue(section, int.Parse(propertyValue));
+ } else if (fieldType.IsEnum) {
+ field.SetValue(section, Enum.Parse(fieldType, propertyValue));
+ }
+ }
+ }
+ }
+ return section;
+ }
+
+ public IniSection GetSection(Type iniSectionType) {
+ IniSection section = null;
+ string sectionName = getSectionName(iniSectionType);
+ if (sectionMap.ContainsKey(sectionName)) {
+ section = sectionMap[sectionName];
+ } else {
+ // Create instance of this type
+ section = (IniSection)Activator.CreateInstance(iniSectionType);
+
+ // Get the properties for the section
+ Dictionary properties = null;
+ if (iniProperties.ContainsKey(sectionName)) {
+ properties = iniProperties[sectionName];
+ }
+
+ // Iterate over the fields and fill them
+ FieldInfo[] fields = iniSectionType.GetFields();
+ foreach(FieldInfo field in fields) {
+ if (Attribute.IsDefined(field, typeof(IniPropertyAttribute))) {
+ IniPropertyAttribute iniPropertyAttribute = (IniPropertyAttribute)field.GetCustomAttributes(typeof(IniPropertyAttribute), false)[0];
+ string propertyName = iniPropertyAttribute.Name;
+ string propertyValue = null;
+ // Get the value from the ini file, if there is none take the default
+ if (properties != null && properties.ContainsKey(propertyName)) {
+ propertyValue = properties[propertyName];
+ } else {
+ propertyValue = iniPropertyAttribute.DefaultValue;
+ }
+
+ // Get the type, or the underlying type for nullables
+ Type fieldType = field.FieldType;
+ if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) {
+ // We are dealing with a generic type that is nullable
+ fieldType = Nullable.GetUnderlyingType(fieldType);
+ }
+
+ // Now set the value
+ if (fieldType == typeof(string)) {
+ field.SetValue(section, propertyValue);
+ } else if (fieldType == typeof(bool) || fieldType == typeof(bool?)) {
+ field.SetValue(section, bool.Parse(propertyValue));
+ } else if (fieldType == typeof(int) || fieldType == typeof(int?)) {
+ field.SetValue(section, int.Parse(propertyValue));
+ } else if (fieldType.IsEnum) {
+ field.SetValue(section, Enum.Parse(fieldType, propertyValue));
+ }
+ }
+ }
+ }
+ return section;
+ }
+
+ private string getSectionName(Type iniSectionType) {
+ Attribute[] classAttributes = Attribute.GetCustomAttributes(iniSectionType);
+ foreach(Attribute attribute in classAttributes) {
+ if (attribute is IniSectionAttribute) {
+ IniSectionAttribute iniSectionAttribute = (IniSectionAttribute)attribute;
+ return iniSectionAttribute.Name;
+ }
+ }
+ return null;
+ }
+
+ private Dictionary getProperties(string section) {
+ if (iniProperties.ContainsKey(section)) {
+ return iniProperties[section];
+ }
+ return null;
+ }
+
+ public void ChangeProperty(string section, string name, string value) {
+ if (section != null) {
+ Dictionary properties = iniProperties[section];
+ properties[name] = value;
+ LOG.Debug(String.Format("Changed property {0} to section: {0}.", name, section));
+ } else {
+ LOG.Debug("Property without section: " + name);
+ }
+ }
+
+ public void SetProperty(string section, string name, string value) {
+ if (section != null) {
+ Dictionary properties = null;
+ if (!iniProperties.ContainsKey(section)) {
+ properties = new Dictionary();
+ iniProperties.Add(section, properties);
+ } else {
+ properties = iniProperties[section];
+ }
+ properties.Add(name, value);
+ LOG.Debug(String.Format("Added property {0} to section: {0}.", name, section));
+ } else {
+ LOG.Debug("Property without section: " + name);
+ }
+ }
+
+
+ public bool HasProperty(string section, string name) {
+ Dictionary properties = getProperties(section);
+ if (properties != null && properties.ContainsKey(name)) {
+ return true;
+ }
+ return false;
+ }
+
+ public string GetProperty(string section, string name) {
+ Dictionary properties = getProperties(section);
+ if (properties != null && properties.ContainsKey(name)) {
+ return properties[name];
+ }
+ return null;
+ }
+
+ ///
+ /// Split property with ',' and return the splitted string as a string[]
+ ///
+ public string[] GetPropertyAsArray(string section, string key) {
+ Dictionary properties = getProperties(section);
+ string value = GetProperty(section, key);
+ if (value != null) {
+ return value.Split(new Char[] {','});
+ }
+ return null;
+ }
+
+ public bool GetBoolProperty(string section, string key) {
+ Dictionary properties = getProperties(section);
+ string value = GetProperty(section, key);
+ return bool.Parse(value);
+ }
+
+ public int GetIntProperty(string section, string key) {
+ Dictionary properties = getProperties(section);
+ string value = GetProperty(section, key);
+ return int.Parse(value);
+ }
+
+ public void Save() {
+ LOG.Info("Saving configuration to: " + iniLocation);
+ TextWriter writer = new StreamWriter(iniLocation);
+ foreach(IniSection section in sectionMap.Values) {
+ Type classType = section.GetType();
+ Attribute[] classAttributes = Attribute.GetCustomAttributes(classType);
+ foreach(Attribute attribute in classAttributes) {
+ if (attribute is IniSectionAttribute) {
+ IniSectionAttribute iniSectionAttribute = (IniSectionAttribute)attribute;
+ writer.WriteLine("; {0}", iniSectionAttribute.Description);
+ writer.WriteLine("[{0}]", iniSectionAttribute.Name);
+ FieldInfo[] fields = classType.GetFields();
+ foreach(FieldInfo field in fields) {
+ if (Attribute.IsDefined(field, typeof(IniPropertyAttribute))) {
+ IniPropertyAttribute iniPropertyAttribute = (IniPropertyAttribute)field.GetCustomAttributes(typeof(IniPropertyAttribute), false)[0];
+ writer.WriteLine("; {0}", iniPropertyAttribute.Description);
+ object value = field.GetValue(section);
+ if (value == null) {
+ value = iniPropertyAttribute.DefaultValue;
+ }
+ writer.WriteLine("{0}={1}", iniPropertyAttribute.Name, value);
+ }
+ }
+ }
+ }
+ writer.WriteLine();
+ }
+
+ // Write left over properties
+ foreach(string sectionName in iniProperties.Keys) {
+ // Check if the section is one that is "registered", if so skip it!
+ if (!sectionMap.ContainsKey(sectionName)) {
+ // Write section name
+ writer.WriteLine("[{0}]", sectionName);
+ Dictionary properties = iniProperties[sectionName];
+ // Loop and write properties
+ foreach(string propertyName in properties.Keys) {
+ writer.WriteLine("{0}={1}", propertyName, properties[propertyName]);
+ }
+ }
+ }
+ writer.Close();
+ }
+ }
+}
diff --git a/GreenshotCore/GreenshotCore.csproj b/GreenshotCore/GreenshotCore.csproj
index 5368d4af0..51b00f8ac 100644
--- a/GreenshotCore/GreenshotCore.csproj
+++ b/GreenshotCore/GreenshotCore.csproj
@@ -62,9 +62,11 @@
+
+