PageRenderTime 29ms CodeModel.GetById 5ms RepoModel.GetById 0ms app.codeStats 1ms

/ReflectionStudio/ReflectionStudio.Controls/Helpers/ThemeManager.cs

#
C# | 370 lines | 260 code | 47 blank | 63 comment | 33 complexity | 18ff3f985e244565f5bc115fcb58644b MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Windows;
  6. using System.Xml;
  7. using System.Xml.Serialization;
  8. using ReflectionStudio.Core.Events;
  9. using ReflectionStudio.Core.FileManagement;
  10. using ReflectionStudio.Core;
  11. namespace ReflectionStudio.Controls.Helpers
  12. {
  13. /// <summary>
  14. /// ThemeElementCollection is used to serialize only
  15. /// </summary>
  16. [Serializable]
  17. public class ThemeElementCollection
  18. {
  19. [XmlElement("ThemeElement")]
  20. public List<ThemeElement> ThemeElement { get; set; }
  21. }
  22. /// <summary>
  23. /// ThemeElement is used to serialize and maintain the configuration
  24. /// </summary>
  25. [Serializable]
  26. public class ThemeElement
  27. {
  28. [XmlAttribute]
  29. public string Name { get; set; }
  30. [XmlAttribute]
  31. public string Group { get; set; }
  32. [XmlAttribute]
  33. public bool IsSelected { get; set; }
  34. [XmlAttribute]
  35. public bool IsDefault { get; set; }
  36. [XmlAttribute]
  37. public string Image { get; set; }
  38. [XmlElement("Dictionary")]
  39. public List<string> Dictionaries { get; set; }
  40. }
  41. /// <summary>
  42. /// ThemeManager helps managing themes as an association of a skin and a color. It discover resources in a configuration file as a collection
  43. /// of ThemeElement that contains skins and colors.
  44. /// </summary>
  45. public class ThemeManager
  46. {
  47. #region ----------------SINGLETON----------------
  48. /// <summary>
  49. /// Singleton instance
  50. /// </summary>
  51. public static readonly ThemeManager Instance = new ThemeManager();
  52. /// <summary>
  53. /// Private constructor for singleton pattern
  54. /// </summary>
  55. private ThemeManager()
  56. {
  57. }
  58. #endregion
  59. #region ----------------PROPERTIES----------------
  60. private List<ThemeElement> _ThemeElements = null;
  61. /// <summary>
  62. /// All the theme elements available in the embedded configuration file
  63. /// </summary>
  64. public List<ThemeElement> ThemeElements
  65. {
  66. get
  67. {
  68. if (_ThemeElements == null)
  69. _ThemeElements = new List<ThemeElement>();
  70. return _ThemeElements;
  71. }
  72. }
  73. /// <summary>
  74. /// get/set the selected skin in the collection
  75. /// </summary>
  76. public ThemeElement CurrentSkin
  77. {
  78. get { return ThemeElements.Where(p => p.IsSelected == true && p.Group == "Skins").First(); }
  79. set { LoadThemeResource(value); }
  80. }
  81. /// <summary>
  82. /// get/set the selected color in the collection
  83. /// </summary>
  84. public ThemeElement CurrentColor
  85. {
  86. get { return ThemeElements.Where(p => p.IsSelected == true && p.Group == "Colors").First(); }
  87. set { LoadThemeResource(value); }
  88. }
  89. #endregion
  90. #region ----------------METHODS----------------
  91. /// <summary>
  92. /// Load a ThemeElement into the application dictionnaries
  93. /// </summary>
  94. /// <param name="themeResource"></param>
  95. public void LoadThemeResource(ThemeElement themeResource)
  96. {
  97. Tracer.Verbose("ThemeManager:LoadThemeResource", "START");
  98. //TraceDictionnaries();
  99. Application.Current.Resources.BeginInit();
  100. try
  101. {
  102. //unload the previous same resource type, load the new one
  103. LoadDictionaries(ThemeElements.Where(p => p.Group == themeResource.Group && p.IsSelected == true).First(),
  104. themeResource);
  105. }
  106. catch (Exception all)
  107. {
  108. Tracer.Error("ThemeManager.LoadThemeResource", all);
  109. }
  110. Application.Current.Resources.EndInit();
  111. //TraceDictionnaries();
  112. Tracer.Verbose("ThemeManager:LoadThemeResource", "END");
  113. }
  114. /// <summary>
  115. /// Save the configuration to the disk with the current selected resource
  116. /// </summary>
  117. /// <returns></returns>
  118. public bool Save()
  119. {
  120. Tracer.Verbose("ThemeManager:Save", "START");
  121. bool result = false;
  122. try
  123. {
  124. ThemeElementCollection col = new ThemeElementCollection();
  125. col.ThemeElement = _ThemeElements;
  126. result = SerializeHelper.Serialize(Path.Combine(PathHelper.ApplicationPath, "ThemeManagerConfig.xml"), col, true);
  127. }
  128. catch (Exception all)
  129. {
  130. Tracer.Error("ThemeManager.Save", all);
  131. }
  132. Tracer.Verbose("ThemeManager:Save", "END");
  133. return result;
  134. }
  135. /// <summary>
  136. /// Load the configuration file from disk or from resource if it does not exist
  137. /// </summary>
  138. public void Load()
  139. {
  140. Tracer.Verbose("ThemeManager:Load", "START");
  141. try
  142. {
  143. string file = Path.Combine(PathHelper.ApplicationPath, "ThemeManagerConfig.xml");
  144. // if found in current directory
  145. if (File.Exists(file))
  146. {
  147. using (Stream s = File.OpenRead(file))
  148. {
  149. if (s == null)
  150. throw new InvalidOperationException("Could not open themes file");
  151. ThemeElementCollection elem = (ThemeElementCollection)SerializeHelper.Deserialize(s, typeof(ThemeElementCollection), true);
  152. _ThemeElements = elem.ThemeElement;
  153. //load selected resources
  154. InitializeResource(_ThemeElements.Where(p => p.IsSelected == true).ToList());
  155. }
  156. }
  157. else
  158. {
  159. //load the config from resources
  160. using (Stream s = Application.ResourceAssembly.GetManifestResourceStream("ReflectionStudio.Resources.Embedded.ThemeManagerConfig.xml"))
  161. {
  162. if (s == null)
  163. throw new InvalidOperationException("Could not find embedded resource");
  164. ThemeElementCollection elem = (ThemeElementCollection)SerializeHelper.Deserialize(s, typeof(ThemeElementCollection), true);
  165. _ThemeElements = elem.ThemeElement;
  166. //load default resources
  167. InitializeResource(_ThemeElements.Where(p => p.IsDefault == true).ToList());
  168. }
  169. }
  170. }
  171. catch (Exception all)
  172. {
  173. Tracer.Error("ThemeManager.Load", all);
  174. }
  175. Tracer.Verbose("ThemeManager:Load", "END");
  176. }
  177. #endregion
  178. #region ----------------INTERNALS----------------
  179. /// <summary>
  180. /// Load the specified ThemeElement liste and remove old ones
  181. /// </summary>
  182. /// <param name="themeResourceList"></param>
  183. private void InitializeResource(List<ThemeElement> themeResourceList)
  184. {
  185. Tracer.Verbose("ThemeManager:InitializeResource", "START");
  186. //TraceDictionnaries();
  187. try
  188. {
  189. Application.Current.Resources.BeginInit();
  190. //remove old ones
  191. List<ResourceDictionary> olds = new List<ResourceDictionary>();
  192. List<string> newsItems = new List<string>();
  193. foreach (ThemeElement element in themeResourceList)
  194. newsItems.AddRange(element.Dictionaries);
  195. foreach (string dico in newsItems)
  196. {
  197. //in existing dictionnary, be sure to remove old ones, in particular the on comming from xaml like App.xaml
  198. foreach (ResourceDictionary dictionnary in Application.Current.Resources.MergedDictionaries)
  199. {
  200. if (newsItems.Find(p => p == dictionnary.Source.OriginalString) == null)
  201. olds.Add(dictionnary);
  202. }
  203. }
  204. foreach (ResourceDictionary dictionnary in olds)
  205. Application.Current.Resources.MergedDictionaries.Remove(dictionnary);
  206. foreach (ThemeElement element in themeResourceList)
  207. //add new ones
  208. LoadDictionaries(element);
  209. Application.Current.Resources.EndInit();
  210. }
  211. catch (Exception all)
  212. {
  213. Tracer.Error("ThemeManager.InitializeResource", all);
  214. }
  215. //TraceDictionnaries();
  216. Tracer.Verbose("ThemeManager:InitializeResource", "END");
  217. }
  218. /// <summary>
  219. /// Load the specified ThemeElement in the application and set it as IsSelected
  220. /// </summary>
  221. /// <param name="oldThemeResource"></param>
  222. /// <param name="newThemeResource"></param>
  223. private void LoadDictionaries(ThemeElement oldThemeResource, ThemeElement newThemeResource)
  224. {
  225. Tracer.Verbose("ThemeManager:LoadDictionaries", "START");
  226. try
  227. {
  228. try
  229. {
  230. foreach (string dictionnary in oldThemeResource.Dictionaries)
  231. {
  232. ResourceDictionary dic = Application.Current.Resources.MergedDictionaries.FirstOrDefault(p => p.Source.OriginalString == dictionnary);
  233. if (dic != null)
  234. {
  235. //does not exist in new ones
  236. if (newThemeResource.Dictionaries.Where(p => p == dic.Source.OriginalString).Count() == 0)
  237. Application.Current.Resources.MergedDictionaries.Remove(dic);
  238. }
  239. }
  240. oldThemeResource.IsSelected = false;
  241. }
  242. catch (Exception all)
  243. {
  244. Tracer.Error("ThemeManager.LoadDictionaries", all);
  245. }
  246. foreach (string dictionnary in newThemeResource.Dictionaries)
  247. {
  248. //if does not exist in application
  249. if (Application.Current.Resources.MergedDictionaries.Where(p => p.Source.OriginalString == dictionnary).Count() == 0)
  250. {
  251. Uri Source = new Uri(dictionnary, UriKind.Relative);
  252. ResourceDictionary dico = (ResourceDictionary)Application.LoadComponent(Source);
  253. dico.Source = Source;
  254. Application.Current.Resources.MergedDictionaries.Add(dico);
  255. }
  256. }
  257. newThemeResource.IsSelected = true;
  258. }
  259. catch (Exception all)
  260. {
  261. Tracer.Error("ThemeManager.LoadDictionaries", all);
  262. }
  263. Tracer.Verbose("ThemeManager:LoadDictionaries", "END");
  264. }
  265. /// <summary>
  266. /// Load the specified ThemeElement in the application and set it as IsSelected
  267. /// </summary>
  268. /// <param name="themeResource"></param>
  269. private void LoadDictionaries(ThemeElement themeResource)
  270. {
  271. Tracer.Verbose("ThemeManager:LoadDictionaries", "START");
  272. try
  273. {
  274. foreach (string dictionnary in themeResource.Dictionaries)
  275. {
  276. if (Application.Current.Resources.MergedDictionaries.Where(p => p.Source.OriginalString == dictionnary).Count() == 0)
  277. {
  278. Uri Source = new Uri(dictionnary, UriKind.Relative);
  279. ResourceDictionary dico = (ResourceDictionary)Application.LoadComponent(Source);
  280. dico.Source = Source;
  281. Application.Current.Resources.MergedDictionaries.Add(dico);
  282. }
  283. }
  284. themeResource.IsSelected = true;
  285. }
  286. catch (Exception all)
  287. {
  288. Tracer.Error("ThemeManager.LoadDictionaries", all);
  289. }
  290. Tracer.Verbose("ThemeManager:LoadDictionaries", "END");
  291. }
  292. private void TraceDictionnaries()
  293. {
  294. try
  295. {
  296. foreach (ResourceDictionary dictionnary in Application.Current.Resources.MergedDictionaries)
  297. {
  298. TraceRecursiveDictionnaries(dictionnary);
  299. }
  300. }
  301. catch (Exception all)
  302. {
  303. Tracer.Error("ThemeManager.TraceDictionnaries", all);
  304. }
  305. }
  306. private void TraceRecursiveDictionnaries(ResourceDictionary dico)
  307. {
  308. try
  309. {
  310. Tracer.Verbose("Dico :", dico.Source.ToString() );
  311. foreach (ResourceDictionary dictionnary in dico.MergedDictionaries)
  312. {
  313. TraceRecursiveDictionnaries(dictionnary);
  314. }
  315. }
  316. catch (Exception all)
  317. {
  318. Tracer.Error("ThemeManager.TraceRecursiveDictionnaries", all);
  319. }
  320. }
  321. #endregion
  322. }
  323. }