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

/Excel.Expressions/Classes/Cell.cs

#
C# | 499 lines | 447 code | 47 blank | 5 comment | 56 complexity | 557b75eaf6c0d2842bfef39b6b4fe2ce MD5 | raw file
  1. //-----------------------------------------------------------------------
  2. // <copyright>
  3. // Copyright (c) Artur Mustafin. All rights reserved.
  4. // </copyright>
  5. //-----------------------------------------------------------------------
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Globalization;
  9. using System.Text;
  10. using Excel.Expressions.Compiler;
  11. namespace Excel.Expressions.Classes
  12. {
  13. public class Cell
  14. {
  15. #if DEBUG
  16. private string _inputReferencesText;
  17. private string _outputReferencesText;
  18. #endif
  19. private int _id;
  20. private readonly int _row;
  21. private readonly int _column;
  22. private const int size = 256;
  23. private static Cell[,] _cells = new Cell[size, size];
  24. static Cell()
  25. {
  26. for (int i = 0; i < size; i++)
  27. {
  28. for (int j = 0; j < size; j++)
  29. {
  30. _cells[i, j] = new Cell(i * size + j, i, j);
  31. }
  32. }
  33. }
  34. private bool _visited = false;
  35. private double _value;
  36. private CellExpression _expression;
  37. private readonly string _name;
  38. private Cell(int id, int row, int column)
  39. {
  40. _id = id;
  41. _row = row;
  42. _column = column;
  43. _name = string.Format("{0}{1}", Cell.GetRow(row), Cell.GetCol(column));
  44. _inputReferences = new HashSet<Cell>();
  45. _outputReferences = new HashSet<Cell>();
  46. }
  47. public static string GetRow(int rowIndex)
  48. {
  49. rowIndex += 1;
  50. List<char> chars = new List<char>();
  51. do
  52. {
  53. if (rowIndex % 26 == 0)
  54. {
  55. chars.Add('Z');
  56. rowIndex /= 26;
  57. rowIndex -= 1;
  58. continue;
  59. }
  60. char ch = (char)('@' + rowIndex % 26);
  61. chars.Add(ch);
  62. rowIndex /= 26;
  63. } while (rowIndex > 0);
  64. chars.Reverse();
  65. return new string(chars.ToArray());
  66. }
  67. internal static int GetRow(string name)
  68. {
  69. int rowIndex = 0;
  70. foreach (char ch in name)
  71. {
  72. rowIndex *= 26;
  73. rowIndex += (ch - 'A' + 1);
  74. }
  75. return rowIndex - 1;
  76. }
  77. public static string GetCol(int colIndex)
  78. {
  79. List<char> chars = new List<char>();
  80. do
  81. {
  82. char ch = (char)('0' + colIndex % 10);
  83. chars.Add(ch);
  84. colIndex /= 10;
  85. } while (colIndex > 0);
  86. chars.Reverse();
  87. return new string(chars.ToArray());
  88. }
  89. internal static int GetCol(string name)
  90. {
  91. int colIndex = 0;
  92. foreach (char ch in name)
  93. {
  94. colIndex = colIndex * 10 + ch - '0';
  95. }
  96. return colIndex;
  97. }
  98. public int Id
  99. {
  100. get
  101. {
  102. return _id;
  103. }
  104. }
  105. public static Cell GetCell(int row, int column)
  106. {
  107. return _cells[row, column];
  108. }
  109. public bool HasExpression
  110. {
  111. get
  112. {
  113. return _expression != null;
  114. }
  115. }
  116. public void Eval()
  117. {
  118. if (_visited == false)
  119. {
  120. _visited = true;
  121. if (_expression != null)
  122. {
  123. _value = _expression.Eval();
  124. }
  125. else
  126. {
  127. _value = 0;
  128. }
  129. if (_outputReferences.Count > 0)
  130. {
  131. foreach (Cell cell in _outputReferences)
  132. {
  133. cell.Eval();
  134. }
  135. }
  136. }
  137. }
  138. public void Visit(Action<Cell> action)
  139. {
  140. if (_visited == true)
  141. {
  142. _visited = false;
  143. if (_inputReferences.Count > 0)
  144. {
  145. foreach (var cell in _inputReferences)
  146. {
  147. cell.Visit(action);
  148. }
  149. }
  150. Eval();
  151. if (action != null)
  152. {
  153. action(this);
  154. }
  155. }
  156. }
  157. public double Double
  158. {
  159. get
  160. {
  161. return _value;
  162. }
  163. }
  164. public CellExpression Expression
  165. {
  166. get
  167. {
  168. return _expression;
  169. }
  170. set
  171. {
  172. if (_expression != value)
  173. {
  174. _expression = value;
  175. _visited = false;
  176. Eval();
  177. }
  178. }
  179. }
  180. public int Column
  181. {
  182. get
  183. {
  184. return _column;
  185. }
  186. }
  187. public int Row
  188. {
  189. get
  190. {
  191. return _row;
  192. }
  193. }
  194. public string Value
  195. {
  196. get
  197. {
  198. if (_expression != null)
  199. {
  200. return _value.ToString(CultureInfo.InvariantCulture.NumberFormat);
  201. }
  202. return string.Empty;
  203. }
  204. }
  205. private string _text;
  206. public string Text
  207. {
  208. get
  209. {
  210. return _text;
  211. }
  212. set
  213. {
  214. _text = value;
  215. }
  216. }
  217. private readonly HashSet<Cell> _outputReferences;
  218. private readonly HashSet<Cell> _inputReferences;
  219. private void Subscribe(Cell cell)
  220. {
  221. cell.SubscribeInput(this);
  222. SubscribeOutput(cell);
  223. }
  224. private void Unsubscribe(Cell cell)
  225. {
  226. cell.UnsubscribeInput(this);
  227. UnsubscribeOutput(cell);
  228. }
  229. private void SubscribeInput(Cell cell)
  230. {
  231. #if DEBUG
  232. _inputReferencesText = null;
  233. #endif
  234. _inputReferences.Add(cell);
  235. }
  236. private void UnsubscribeInput(Cell cell)
  237. {
  238. #if DEBUG
  239. _inputReferencesText = null;
  240. #endif
  241. _inputReferences.Remove(cell);
  242. }
  243. private void SubscribeOutput(Cell cell)
  244. {
  245. #if DEBUG
  246. _outputReferencesText = null;
  247. #endif
  248. _outputReferences.Add(cell);
  249. }
  250. private void UnsubscribeOutput(Cell cell)
  251. {
  252. #if DEBUG
  253. _outputReferencesText = null;
  254. #endif
  255. _outputReferences.Remove(cell);
  256. }
  257. public void Clear()
  258. {
  259. #if DEBUG
  260. _inputReferencesText = null;
  261. _outputReferencesText = null;
  262. #endif
  263. _inputReferences.Clear();
  264. _outputReferences.Clear();
  265. _expression = null;
  266. _text = null;
  267. _value = 0;
  268. }
  269. public void Subscribe()
  270. {
  271. HashSet<Cell> outputReferences = new HashSet<Cell>();
  272. Decompile(outputReferences, Expression);
  273. foreach (Cell cell in outputReferences)
  274. {
  275. cell.SubscribeInput(this);
  276. this.SubscribeOutput(cell);
  277. }
  278. }
  279. public void Unsubscribe()
  280. {
  281. HashSet<Cell> outputReferences = new HashSet<Cell>();
  282. Decompile(outputReferences, Expression);
  283. foreach (Cell cell in outputReferences)
  284. {
  285. cell.UnsubscribeInput(this);
  286. this.UnsubscribeOutput(cell);
  287. }
  288. }
  289. #if DEBUG
  290. public override string ToString()
  291. {
  292. if (_inputReferencesText == null)
  293. {
  294. _inputReferencesText = GetReferences(_inputReferences, _inputReferences.Count);
  295. }
  296. if (_outputReferencesText == null)
  297. {
  298. _outputReferencesText = GetReferences(_outputReferences, _outputReferences.Count);
  299. }
  300. bool inputIsNull = string.IsNullOrEmpty(_inputReferencesText);
  301. bool outputIsNull = string.IsNullOrEmpty(_outputReferencesText);
  302. if (!inputIsNull && !outputIsNull)
  303. {
  304. return string.Format("{0}->{1}->{2}", _outputReferencesText, _name, _inputReferencesText);
  305. }
  306. if (!inputIsNull)
  307. {
  308. return string.Format("{0}->{1}", _name, _inputReferencesText);
  309. }
  310. if (!outputIsNull)
  311. {
  312. return string.Format("{0}->{1}", _outputReferencesText, _name);
  313. }
  314. return _name;
  315. }
  316. #else
  317. public override string ToString()
  318. {
  319. return _name;
  320. }
  321. #endif
  322. private string GetReferences(IEnumerable<Cell> cells, int count)
  323. {
  324. IEnumerator<Cell> enumerator = cells.GetEnumerator();
  325. StringBuilder sb = new StringBuilder();
  326. if (enumerator.MoveNext())
  327. {
  328. Cell cell = enumerator.Current;
  329. sb.Append(cell.Name);
  330. int index = 0;
  331. while (enumerator.MoveNext())
  332. {
  333. if (index == 0 && index < count - 2)
  334. {
  335. sb.Append(",...");
  336. index++;
  337. continue;
  338. }
  339. if (index > 0 && index < count - 2)
  340. {
  341. index++;
  342. continue;
  343. }
  344. cell = enumerator.Current;
  345. sb.Append(',');
  346. sb.Append(cell.Name);
  347. index++;
  348. }
  349. }
  350. return sb.ToString();
  351. }
  352. public string Name
  353. {
  354. get
  355. {
  356. return _name;
  357. }
  358. }
  359. public bool Validate(CellExpression expression)
  360. {
  361. foreach (Cell cell in Decompile(expression))
  362. {
  363. if (cell == this)
  364. {
  365. return false;
  366. }
  367. }
  368. return true;
  369. }
  370. private HashSet<Cell> Decompile(CellExpression expression)
  371. {
  372. HashSet<Cell> cells = new HashSet<Cell>();
  373. Decompile(cells, expression);
  374. return cells;
  375. }
  376. public void Decompile(HashSet<Cell> cells, CellExpression expression)
  377. {
  378. if (expression != null)
  379. {
  380. Stack<CellExpression> expressions = new Stack<CellExpression>();
  381. expressions.Push(expression);
  382. do
  383. {
  384. CellExpression current = expressions.Pop();
  385. if (current.Children != null)
  386. {
  387. foreach (CellExpression node in current.Children)
  388. {
  389. CellReference reference = node as CellReference;
  390. if (reference != null)
  391. {
  392. if (cells.Add(reference.Cell))
  393. {
  394. if (reference.Cell.Expression != null)
  395. {
  396. expressions.Push(reference.Cell.Expression);
  397. }
  398. }
  399. }
  400. else
  401. {
  402. if (node != null)
  403. {
  404. expressions.Push(node);
  405. }
  406. }
  407. }
  408. }
  409. CellReference referenced = current as CellReference;
  410. if (referenced != null)
  411. {
  412. if (cells.Add(referenced.Cell))
  413. {
  414. if (referenced.Cell.Expression != null)
  415. {
  416. expressions.Push(referenced.Cell.Expression);
  417. }
  418. }
  419. }
  420. }
  421. while (expressions.Count > 0);
  422. }
  423. }
  424. private string _updateText;
  425. private CellExpression _updateExpression;
  426. public void BeginUpdate()
  427. {
  428. _updateText = _text;
  429. _updateExpression = _expression;
  430. }
  431. public void EndUpdate()
  432. {
  433. _updateText = null;
  434. _updateExpression = null;
  435. }
  436. public void CancelUpdate()
  437. {
  438. _text = _updateText;
  439. _expression = _updateExpression;
  440. }
  441. internal static Range GetRange(int id1, int id2)
  442. {
  443. if (id1 > id2)
  444. {
  445. int temp = id1;
  446. id1 = id2;
  447. id2 = temp;
  448. }
  449. return new Range(id1 / size, id1 % size, id2 / size, id2 % size);
  450. }
  451. }
  452. }