PageRenderTime 27ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/Project.AutoFix/Src/StyleCop/Settings/PropertyControl.cs

#
C# | 539 lines | 302 code | 80 blank | 157 comment | 40 complexity | 316a3dbbdfe365de498f1bd29ab4885f MD5 | raw file
Possible License(s): CC-BY-SA-3.0
  1. //-----------------------------------------------------------------------
  2. // <copyright file="PropertyControl.cs">
  3. // MS-PL
  4. // </copyright>
  5. // <license>
  6. // This source code is subject to terms and conditions of the Microsoft
  7. // Public License. A copy of the license can be found in the License.html
  8. // file at the root of this distribution.
  9. // By using this source code in any fashion, you are agreeing to be bound
  10. // by the terms of the Microsoft Public License. You must not remove this
  11. // notice, or any other, from this software.
  12. // </license>
  13. //-----------------------------------------------------------------------
  14. namespace StyleCop
  15. {
  16. using System;
  17. using System.Collections.Generic;
  18. using System.Drawing;
  19. using System.Globalization;
  20. using System.Windows.Forms;
  21. /// <summary>
  22. /// The possible results of saving the settings.
  23. /// </summary>
  24. internal enum PropertyControlSaveResult
  25. {
  26. /// <summary>
  27. /// The save succeeded.
  28. /// </summary>
  29. Success,
  30. /// <summary>
  31. /// One of the pages aborted the save operation.
  32. /// </summary>
  33. PageAbort,
  34. /// <summary>
  35. /// An error occurred while saving the file.
  36. /// </summary>
  37. SaveError
  38. }
  39. /// <summary>
  40. /// Interface which must be implemented by a host of the <see cref="PropertyControl"/>.
  41. /// </summary>
  42. internal interface IPropertyControlHost
  43. {
  44. #region Methods
  45. /// <summary>
  46. /// Called when the combined dirty status of the pages changes.
  47. /// </summary>
  48. /// <param name="isDirty">True if any of the pages are dirty, false if not.</param>
  49. void Dirty(bool isDirty);
  50. /// <summary>
  51. /// Called to cancel the host.
  52. /// </summary>
  53. void Cancel();
  54. #endregion Methods
  55. }
  56. /// <summary>
  57. /// Hosts property pages.
  58. /// </summary>
  59. public class PropertyControl : TabControl
  60. {
  61. #region Private Fields
  62. /// <summary>
  63. /// Indicates whether any of the pages are dirty.
  64. /// </summary>
  65. private bool dirty;
  66. /// <summary>
  67. /// The pages to display.
  68. /// </summary>
  69. private UserControl[] pages;
  70. /// <summary>
  71. /// The pages to display.
  72. /// </summary>
  73. private TabPage[] tabPages;
  74. /// <summary>
  75. /// The pages to display.
  76. /// </summary>
  77. private IList<IPropertyControlPage> pageInterfaces;
  78. /// <summary>
  79. /// The property page host.
  80. /// </summary>
  81. private IPropertyControlHost host;
  82. /// <summary>
  83. /// The StyleCop core instance.
  84. /// </summary>
  85. private StyleCopCore core;
  86. /// <summary>
  87. /// The settings file to read from and write to.
  88. /// </summary>
  89. private WritableSettings localSettings;
  90. /// <summary>
  91. /// The local settings merged with parent settings.
  92. /// </summary>
  93. private Settings mergedSettings;
  94. /// <summary>
  95. /// The settings one level up from the local settings file.
  96. /// </summary>
  97. private Settings parentSettings;
  98. /// <summary>
  99. /// Compares the local settings with the merged settings.
  100. /// </summary>
  101. private SettingsComparer settingsComparer;
  102. /// <summary>
  103. /// The context for the property pages.
  104. /// </summary>
  105. private object[] context;
  106. #endregion Private Fields
  107. #region Internal Constructors
  108. /// <summary>
  109. /// Initializes a new instance of the PropertyControl class.
  110. /// </summary>
  111. internal PropertyControl()
  112. {
  113. this.InitializeComponent();
  114. }
  115. #endregion Internal Constructors
  116. #region Public Properties
  117. /// <summary>
  118. /// Gets a value indicating whether any of the pages are dirty.
  119. /// </summary>
  120. public bool IsDirty
  121. {
  122. get
  123. {
  124. return this.dirty;
  125. }
  126. }
  127. /// <summary>
  128. /// Gets the list of pages that are currently loaded on the property control.
  129. /// </summary>
  130. public IList<IPropertyControlPage> Pages
  131. {
  132. get
  133. {
  134. return this.pageInterfaces;
  135. }
  136. }
  137. /// <summary>
  138. /// Gets the currently active page.
  139. /// </summary>
  140. public IPropertyControlPage ActivePage
  141. {
  142. get
  143. {
  144. if (this.host != null)
  145. {
  146. return this.pageInterfaces[this.SelectedIndex];
  147. }
  148. return null;
  149. }
  150. }
  151. /// <summary>
  152. /// Gets the StyleCop core instance.
  153. /// </summary>
  154. public StyleCopCore Core
  155. {
  156. get
  157. {
  158. return this.core;
  159. }
  160. }
  161. /// <summary>
  162. /// Gets the local settings file to read from and write to.
  163. /// </summary>
  164. public WritableSettings LocalSettings
  165. {
  166. get
  167. {
  168. return this.localSettings;
  169. }
  170. }
  171. /// <summary>
  172. /// Gets the local settings merged with all parent settings.
  173. /// </summary>
  174. public Settings MergedSettings
  175. {
  176. get
  177. {
  178. return this.mergedSettings;
  179. }
  180. }
  181. /// <summary>
  182. /// Gets the settings which the local settings are merged with at runtime, or null if there are
  183. /// no settings to merge.
  184. /// </summary>
  185. public Settings ParentSettings
  186. {
  187. get
  188. {
  189. return this.parentSettings;
  190. }
  191. }
  192. /// <summary>
  193. /// Gets a comparer that can be used to determine whether local settings are overriding parent settings.
  194. /// </summary>
  195. public SettingsComparer SettingsComparer
  196. {
  197. get
  198. {
  199. return this.settingsComparer;
  200. }
  201. }
  202. /// <summary>
  203. /// Gets the list of context objects passed to this property control.
  204. /// </summary>
  205. public IList<object> Context
  206. {
  207. get
  208. {
  209. return this.context;
  210. }
  211. }
  212. #endregion Public Properties
  213. #region Public Methods
  214. /// <summary>
  215. /// Sets the dirty flag and notifies the host that the dirty status has changed.
  216. /// </summary>
  217. public void DirtyChanged()
  218. {
  219. bool pageDirty = false;
  220. foreach (IPropertyControlPage page in this.pageInterfaces)
  221. {
  222. if (page != null && page.Dirty)
  223. {
  224. pageDirty = true;
  225. break;
  226. }
  227. }
  228. if (pageDirty != this.dirty)
  229. {
  230. this.dirty = pageDirty;
  231. this.host.Dirty(pageDirty);
  232. }
  233. }
  234. /// <summary>
  235. /// Called when the property control should be cancelled.
  236. /// </summary>
  237. public void Cancel()
  238. {
  239. this.host.Cancel();
  240. }
  241. /// <summary>
  242. /// Called when the parent settings have changed.
  243. /// </summary>
  244. public void RefreshMergedSettings()
  245. {
  246. // Set the contents of the parent settings file.
  247. SettingsMerger merger = new SettingsMerger(this.localSettings, this.core.Environment);
  248. this.parentSettings = merger.ParentMergedSettings;
  249. this.mergedSettings = merger.MergedSettings;
  250. // Set up the settings comparer.
  251. this.settingsComparer = new SettingsComparer(this.localSettings, this.parentSettings);
  252. for (int i = 0; i < this.pageInterfaces.Count; ++i)
  253. {
  254. if (this.pageInterfaces[i] != null)
  255. {
  256. this.pageInterfaces[i].RefreshSettingsOverrideState();
  257. }
  258. }
  259. }
  260. #endregion Public Methods
  261. #region Internal Methods
  262. /// <summary>
  263. /// The control must be initialized by calling this method during the host's OnLoad event.
  264. /// </summary>
  265. /// <param name="hostInstance">Interface implemented by the host object.</param>
  266. /// <param name="propertyPages">The array of pages to display on the tab control.</param>
  267. /// <param name="settings">The settings to read from and write to.</param>
  268. /// <param name="coreInstance">The StyleCop core instance.</param>
  269. /// <param name="contextItem">The context for the property control.</param>
  270. internal void Initialize(
  271. IPropertyControlHost hostInstance,
  272. IList<IPropertyControlPage> propertyPages,
  273. WritableSettings settings,
  274. StyleCopCore coreInstance,
  275. params object[] contextItem)
  276. {
  277. Param.AssertNotNull(hostInstance, "hostInstance");
  278. Param.Assert(propertyPages != null && propertyPages.Count > 0, "propertyPages", "Cannot be null or empty");
  279. Param.AssertNotNull(settings, "settings");
  280. Param.AssertNotNull(coreInstance, "coreInstance");
  281. Param.Ignore(contextItem);
  282. // Make sure we haven't already been intialized.
  283. if (this.host != null)
  284. {
  285. throw new StyleCopException(Strings.PropertyControlAlreadyInitialized);
  286. }
  287. this.host = hostInstance;
  288. this.pageInterfaces = propertyPages;
  289. this.localSettings = settings;
  290. this.core = coreInstance;
  291. this.context = contextItem;
  292. // Set the contents of the parent settings file.
  293. SettingsMerger merger = new SettingsMerger(this.localSettings, this.core.Environment);
  294. this.parentSettings = merger.ParentMergedSettings;
  295. this.mergedSettings = merger.MergedSettings;
  296. // Set up the settings comparer.
  297. this.settingsComparer = new SettingsComparer(this.localSettings, this.parentSettings);
  298. // Make sure the context is non-null.
  299. if (this.context == null)
  300. {
  301. this.context = new object[] { };
  302. }
  303. this.tabPages = new TabPage[propertyPages.Count];
  304. this.pages = new UserControl[propertyPages.Count];
  305. // Add each of the property pages.
  306. int pageCount = 0;
  307. // Initialize the settings pages.
  308. for (int i = 0; i < propertyPages.Count; ++i)
  309. {
  310. this.pages[pageCount] = (UserControl)this.pageInterfaces[i];
  311. TabPage tabPage = new TabPage(this.pageInterfaces[i].TabName);
  312. this.tabPages[pageCount] = tabPage;
  313. tabPage.Controls.Add(this.pages[i]);
  314. this.Controls.Add(tabPage);
  315. this.pages[i].Dock = DockStyle.Fill;
  316. this.SizePage(i);
  317. // The first page has already been initialized.
  318. this.pageInterfaces[i].Initialize(this);
  319. ++pageCount;
  320. }
  321. // Activate the first page.
  322. if (this.TabPages[0] != null)
  323. {
  324. this.SelectedTab = this.tabPages[0];
  325. this.pageInterfaces[0].Activate(true);
  326. }
  327. this.SizeChanged += new System.EventHandler(this.OnSizeChanged);
  328. }
  329. /// <summary>
  330. /// Applies the data on the property pages.
  331. /// </summary>
  332. /// <param name="dirtyPages">Returns true if any pages were dirty.</param>
  333. /// <returns>Returns false if any page returned false from it's apply call, in which case
  334. /// the apply failed.</returns>
  335. internal PropertyControlSaveResult Apply(out bool dirtyPages)
  336. {
  337. dirtyPages = false;
  338. // Call the apply method for each of the pages.
  339. PropertyControlSaveResult result = PropertyControlSaveResult.Success;
  340. bool cancel = false;
  341. bool[] pageDirtyState = new bool[this.pageInterfaces.Count];
  342. // Pre-apply the pages.
  343. for (int i = 0; i < this.pageInterfaces.Count; ++i)
  344. {
  345. if (this.pageInterfaces[i] != null)
  346. {
  347. pageDirtyState[i] = this.pageInterfaces[i].Dirty;
  348. if (!this.pageInterfaces[i].PreApply())
  349. {
  350. cancel = true;
  351. break;
  352. }
  353. }
  354. }
  355. if (!cancel)
  356. {
  357. // Apply the pages.
  358. int breakIndex = -1;
  359. for (int i = 0; i < this.pageInterfaces.Count; ++i)
  360. {
  361. if (this.pageInterfaces[i] != null && this.pageInterfaces[i].Dirty)
  362. {
  363. dirtyPages = true;
  364. if (!this.pageInterfaces[i].Apply())
  365. {
  366. result = PropertyControlSaveResult.PageAbort;
  367. breakIndex = i;
  368. break;
  369. }
  370. }
  371. }
  372. // Post-apply the pages.
  373. int lastIndex = breakIndex == -1 ? this.pageInterfaces.Count - 1 : breakIndex;
  374. for (int i = 0; i <= lastIndex; ++i)
  375. {
  376. if (this.pageInterfaces[i] != null)
  377. {
  378. this.pageInterfaces[i].PostApply(pageDirtyState[i]);
  379. }
  380. }
  381. if (breakIndex == -1)
  382. {
  383. // Save the settings files.
  384. Exception exception = null;
  385. if (!this.core.Environment.SaveSettings(this.localSettings, out exception))
  386. {
  387. AlertDialog.Show(
  388. this.core,
  389. this,
  390. string.Format(CultureInfo.CurrentUICulture, Strings.CouldNotSaveSettingsFile, exception.Message),
  391. Strings.Title,
  392. MessageBoxButtons.OK,
  393. MessageBoxIcon.Error);
  394. result = PropertyControlSaveResult.SaveError;
  395. // Reset the dirty flag on each page.
  396. for (int i = 0; i < this.pageInterfaces.Count; ++i)
  397. {
  398. if (this.pageInterfaces[i] != null)
  399. {
  400. this.pageInterfaces[i].Dirty = pageDirtyState[i];
  401. }
  402. }
  403. }
  404. else
  405. {
  406. this.dirty = false;
  407. this.host.Dirty(false);
  408. }
  409. }
  410. }
  411. return result;
  412. }
  413. #endregion Internal Methods
  414. #region Private Methods
  415. #region Component Designer generated code
  416. /// <summary>
  417. /// Required method for Designer support - do not modify
  418. /// the contents of this method with the code editor.
  419. /// </summary>
  420. private void InitializeComponent()
  421. {
  422. this.SuspendLayout();
  423. //
  424. // PropertyControl
  425. //
  426. this.Controls.AddRange(new System.Windows.Forms.Control[] {
  427. });
  428. this.Name = "PropertyControl";
  429. this.Size = new System.Drawing.Size(248, 216);
  430. this.ResumeLayout(false);
  431. }
  432. #endregion
  433. /// <summary>
  434. /// Called when the size of the dialog changes.
  435. /// </summary>
  436. /// <param name="sender">The event sender..</param>
  437. /// <param name="e">The event arguments.</param>
  438. private void OnSizeChanged(object sender, System.EventArgs e)
  439. {
  440. Param.Ignore(sender, e);
  441. if (this.SelectedIndex >= 0)
  442. {
  443. this.SizePage(this.SelectedIndex);
  444. }
  445. }
  446. /// <summary>
  447. /// Sets the size of a tab page to fill the sheet area.
  448. /// </summary>
  449. /// <param name="index">The index of the tab to size.</param>
  450. private void SizePage(int index)
  451. {
  452. Param.AssertValueBetween(index, 0, this.tabPages.Length - 1, "index");
  453. Rectangle rect = this.GetTabRect(index);
  454. this.tabPages[index].Height = rect.Height;
  455. this.tabPages[index].Width = rect.Width;
  456. }
  457. #endregion Private Methods
  458. }
  459. }