Dictionary.cs 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Data;
  5. using System.IO;
  6. using FastReport.Utils;
  7. using System.CodeDom;
  8. using System.ComponentModel;
  9. using System.Collections;
  10. using FastReport.CrossView;
  11. using System.Windows.Forms;
  12. namespace FastReport.Data
  13. {
  14. /// <summary>
  15. /// This class stores all report data items such as datasources, connections, relations, parameters,
  16. /// system variables.
  17. /// </summary>
  18. /// <remarks>
  19. /// You can access the report dictionary via <b>Report.Dictionary</b> property.
  20. /// </remarks>
  21. public class Dictionary : Base, IParent
  22. {
  23. #region Fields
  24. private ConnectionCollection connections;
  25. private DataSourceCollection dataSources;
  26. private RelationCollection relations;
  27. private ParameterCollection parameters;
  28. private SystemVariables systemVariables;
  29. private TotalCollection totals;
  30. private CubeSourceCollection cubeSources;
  31. private List<RegDataItem> registeredItems;
  32. private ObjectCollection cachedAllObjects;
  33. private bool cacheAllObjects;
  34. #endregion
  35. #region Properties
  36. /// <summary>
  37. /// Gets a collection of connection objects available in a report.
  38. /// </summary>
  39. public ConnectionCollection Connections
  40. {
  41. get { return connections; }
  42. }
  43. /// <summary>
  44. /// Gets a collection of datasources available in a report.
  45. /// </summary>
  46. /// <remarks>
  47. /// Usually you don't need to use this property. It contains only datasources
  48. /// registered using the <b>RegisterData</b> method. All other datasources are contained
  49. /// in connection objects and may be accessed via <see cref="Connections"/> property.
  50. /// </remarks>
  51. public DataSourceCollection DataSources
  52. {
  53. get { return dataSources; }
  54. }
  55. /// <summary>
  56. /// Gets a collection of relations.
  57. /// </summary>
  58. public RelationCollection Relations
  59. {
  60. get { return relations; }
  61. }
  62. /// <summary>
  63. /// Gets a collection of parameters.
  64. /// </summary>
  65. /// <remarks>
  66. /// Another way to access parameters is to use the <b>Report.Parameters</b> property
  67. /// which is actually a shortcut to this property. You also may use the <b>Report.GetParameter</b>
  68. /// and <b>Report.GetParameterValue</b> methods.
  69. /// </remarks>
  70. public ParameterCollection Parameters
  71. {
  72. get { return parameters; }
  73. }
  74. /// <summary>
  75. /// Gets a collection of system variables like Date, PageNofM etc.
  76. /// </summary>
  77. /// <remarks>
  78. /// Another way to access a system variable is to use the <b>Report.GetVariableValue</b> method.
  79. /// </remarks>
  80. public SystemVariables SystemVariables
  81. {
  82. get { return systemVariables; }
  83. }
  84. /// <summary>
  85. /// Gets a collection of totals.
  86. /// </summary>
  87. /// <remarks>
  88. /// Another way to get a total value is to use the <b>Report.GetTotalValue</b> method.
  89. /// </remarks>
  90. public TotalCollection Totals
  91. {
  92. get { return totals; }
  93. }
  94. /// <summary>
  95. /// Gets a collection of cubesources available in a report.
  96. /// </summary>
  97. /// <remarks>
  98. /// Usually you don't need to use this property. It contains only cubesources
  99. /// registered using the <b>RegisterData</b> method.
  100. /// </remarks>
  101. public CubeSourceCollection CubeSources
  102. {
  103. get { return cubeSources; }
  104. }
  105. /// <summary>
  106. /// Gets a list of registered items.
  107. /// </summary>
  108. /// <remarks>
  109. /// This property is for internal use only.
  110. /// </remarks>
  111. public List<RegDataItem> RegisteredItems
  112. {
  113. get { return registeredItems; }
  114. }
  115. internal bool CacheAllObjects
  116. {
  117. get { return cacheAllObjects; }
  118. set
  119. {
  120. cacheAllObjects = value;
  121. if (cacheAllObjects)
  122. {
  123. cachedAllObjects = base.AllObjects;
  124. }
  125. else
  126. {
  127. cachedAllObjects = null;
  128. }
  129. }
  130. }
  131. ///<inheritdoc/>
  132. public new ObjectCollection AllObjects
  133. {
  134. get
  135. {
  136. if (cachedAllObjects != null)
  137. return cachedAllObjects;
  138. return base.AllObjects;
  139. }
  140. }
  141. #endregion
  142. #region Private Methods
  143. private RegDataItem FindRegisteredItem(object data)
  144. {
  145. foreach (RegDataItem item in registeredItems)
  146. {
  147. if (item.data == data)
  148. return item;
  149. }
  150. return null;
  151. }
  152. private RegDataItem FindRegisteredItem(string name)
  153. {
  154. foreach (RegDataItem item in registeredItems)
  155. {
  156. if (item.name == name)
  157. return item;
  158. }
  159. return null;
  160. }
  161. internal void AddRegisteredItem(object data, string name)
  162. {
  163. if (FindRegisteredItem(data) == null)
  164. registeredItems.Add(new RegDataItem(data, name));
  165. }
  166. #endregion
  167. #region Public Methods
  168. /// <inheritdoc/>
  169. public override void Assign(Base source)
  170. {
  171. BaseAssign(source);
  172. }
  173. internal void RegisterDataSet(DataSet data, string referenceName, bool enabled)
  174. {
  175. DictionaryHelper helper = new DictionaryHelper(this, AllObjects, Report.AllNamedObjects);
  176. helper.RegisterDataSet(data, referenceName, enabled);
  177. }
  178. internal void RegisterDataTable(DataTable table, string referenceName, bool enabled)
  179. {
  180. AddRegisteredItem(table, referenceName);
  181. TableDataSource source = FindDataComponent(referenceName) as TableDataSource;
  182. if (source != null)
  183. {
  184. source.Reference = table;
  185. source.InitSchema();
  186. source.RefreshColumns(true);
  187. }
  188. else
  189. {
  190. // check tables inside connections. Are we trying to replace the connection table
  191. // with table provided by an application?
  192. source = FindByAlias(referenceName) as TableDataSource;
  193. // check "Data.TableName" case
  194. if (source == null && referenceName.StartsWith("Data."))
  195. source = FindByAlias(referenceName.Remove(0, 5)) as TableDataSource;
  196. if (source != null && (source.Connection != null || source.IgnoreConnection))
  197. {
  198. source.IgnoreConnection = true;
  199. source.Reference = table;
  200. source.InitSchema();
  201. source.RefreshColumns(true);
  202. }
  203. else
  204. {
  205. source = new TableDataSource();
  206. source.ReferenceName = referenceName;
  207. source.Reference = table;
  208. source.Name = CreateUniqueName(referenceName.Contains(".") ? table.TableName : referenceName);
  209. source.Alias = CreateUniqueAlias(source.Alias);
  210. source.Enabled = enabled;
  211. source.InitSchema();
  212. DataSources.Add(source);
  213. }
  214. }
  215. }
  216. /// <summary>
  217. /// Registers a DataView.
  218. /// </summary>
  219. /// <param name="view">The DataView to register.</param>
  220. /// <param name="referenceName">The name of the data object.</param>
  221. /// <param name="enabled">Determines wheter to enable the object or not.</param>
  222. /// <remarks>
  223. /// This method is for internal use only.
  224. /// </remarks>
  225. public void RegisterDataView(DataView view, string referenceName, bool enabled)
  226. {
  227. AddRegisteredItem(view, referenceName);
  228. ViewDataSource source = FindDataComponent(referenceName) as ViewDataSource;
  229. if (source != null)
  230. {
  231. source.Reference = view;
  232. source.InitSchema();
  233. source.RefreshColumns();
  234. }
  235. else
  236. {
  237. source = new ViewDataSource();
  238. source.ReferenceName = referenceName;
  239. source.Reference = view;
  240. source.Name = CreateUniqueName(referenceName);
  241. source.Alias = CreateUniqueAlias(source.Alias);
  242. source.Enabled = enabled;
  243. source.InitSchema();
  244. DataSources.Add(source);
  245. }
  246. }
  247. internal void RegisterDataRelation(DataRelation relation, string referenceName, bool enabled)
  248. {
  249. AddRegisteredItem(relation, referenceName);
  250. if (FindDataComponent(referenceName) != null)
  251. return;
  252. Relation rel = new Relation();
  253. rel.ReferenceName = referenceName;
  254. rel.Reference = relation;
  255. rel.Name = relation.RelationName;
  256. rel.Enabled = enabled;
  257. rel.ParentDataSource = FindDataTableSource(relation.ParentTable);
  258. rel.ChildDataSource = FindDataTableSource(relation.ChildTable);
  259. string[] parentColumns = new string[relation.ParentColumns.Length];
  260. string[] childColumns = new string[relation.ChildColumns.Length];
  261. for (int i = 0; i < relation.ParentColumns.Length; i++)
  262. {
  263. parentColumns[i] = relation.ParentColumns[i].Caption;
  264. }
  265. for (int i = 0; i < relation.ChildColumns.Length; i++)
  266. {
  267. childColumns[i] = relation.ChildColumns[i].Caption;
  268. }
  269. rel.ParentColumns = parentColumns;
  270. rel.ChildColumns = childColumns;
  271. Relations.Add(rel);
  272. }
  273. /// <summary>
  274. /// Registers a business object.
  275. /// </summary>
  276. /// <param name="data">The business object.</param>
  277. /// <param name="referenceName">The name of the object.</param>
  278. /// <param name="maxNestingLevel">Maximum level of data nesting.</param>
  279. /// <param name="enabled">Determines wheter to enable the object or not.</param>
  280. /// <remarks>
  281. /// This method is for internal use only.
  282. /// </remarks>
  283. public void RegisterBusinessObject(IEnumerable data, string referenceName, int maxNestingLevel, bool enabled)
  284. {
  285. AddRegisteredItem(data, referenceName);
  286. Type dataType = data.GetType();
  287. if (data is BindingSource)
  288. {
  289. if ((data as BindingSource).DataSource is Type)
  290. dataType = ((data as BindingSource).DataSource as Type);
  291. else
  292. dataType = (data as BindingSource).DataSource.GetType();
  293. }
  294. BusinessObjectConverter converter = new BusinessObjectConverter(this);
  295. BusinessObjectDataSource source = FindDataComponent(referenceName) as BusinessObjectDataSource;
  296. if (source != null)
  297. {
  298. source.Reference = data;
  299. source.DataType = dataType;
  300. converter.UpdateExistingObjects(source, maxNestingLevel);
  301. }
  302. else
  303. {
  304. source = new BusinessObjectDataSource();
  305. source.ReferenceName = referenceName;
  306. source.Reference = data;
  307. source.DataType = dataType;
  308. source.Name = CreateUniqueName(referenceName);
  309. source.Alias = CreateUniqueAlias(source.Alias);
  310. source.Enabled = enabled;
  311. DataSources.Add(source);
  312. converter.CreateInitialObjects(source, maxNestingLevel);
  313. }
  314. }
  315. /// <summary>
  316. /// Registers a CubeLink.
  317. /// </summary>
  318. /// <param name="cubeLink">The CubeLink to register.</param>
  319. /// <param name="referenceName">The name of the data object.</param>
  320. /// <param name="enabled">Determines wheter to enable the object or not.</param>
  321. /// <remarks>
  322. /// This method is for internal use only.
  323. /// </remarks>
  324. public void RegisterCubeLink(IBaseCubeLink cubeLink, string referenceName, bool enabled)
  325. {
  326. AddRegisteredItem(cubeLink, referenceName);
  327. CubeSourceBase source = FindDataComponent(referenceName) as CubeSourceBase;
  328. if (source != null)
  329. {
  330. source.Reference = cubeLink;
  331. }
  332. else
  333. {
  334. source = new SliceCubeSource();
  335. source.ReferenceName = referenceName;
  336. source.Reference = cubeLink;
  337. source.Name = CreateUniqueName(referenceName);
  338. source.Alias = CreateUniqueAlias(source.Alias);
  339. source.Enabled = enabled;
  340. CubeSources.Add(source);
  341. }
  342. }
  343. /// <summary>
  344. /// Registers a data object.
  345. /// </summary>
  346. /// <param name="data">The object to register.</param>
  347. /// <param name="name">The name of the object.</param>
  348. /// <param name="enabled">Determines whether to enable the object or not.</param>
  349. /// <remarks>
  350. /// This method is for internal use only.
  351. /// </remarks>
  352. public void RegisterData(object data, string name, bool enabled)
  353. {
  354. if (data is DataSet)
  355. {
  356. RegisterDataSet(data as DataSet, name, enabled);
  357. }
  358. else if (data is DataTable)
  359. {
  360. RegisterDataTable(data as DataTable, name, enabled);
  361. }
  362. else if (data is DataView)
  363. {
  364. RegisterDataView(data as DataView, name, enabled);
  365. }
  366. else if (data is DataRelation)
  367. {
  368. RegisterDataRelation(data as DataRelation, name, enabled);
  369. }
  370. else if (data is IEnumerable)
  371. {
  372. RegisterBusinessObject(data as IEnumerable, name, 1, enabled);
  373. }
  374. else if (data is IBaseCubeLink)
  375. {
  376. RegisterCubeLink(data as IBaseCubeLink, name, enabled);
  377. }
  378. }
  379. /// <summary>
  380. /// Unregisters the previously registered data.
  381. /// </summary>
  382. /// <param name="data">The application data.</param>
  383. public void UnregisterData(object data)
  384. {
  385. UnregisterData(data, "Data");
  386. }
  387. /// <summary>
  388. /// Unregisters the previously registered data.
  389. /// </summary>
  390. /// <param name="data">The application data.</param>
  391. /// <param name="name">The name of the data.</param>
  392. /// <remarks>
  393. /// You must specify the same <b>data</b> and <b>name</b> as when you call <b>RegisterData</b>.
  394. /// </remarks>
  395. public void UnregisterData(object data, string name)
  396. {
  397. for (int i = 0; i < registeredItems.Count; i++)
  398. {
  399. RegDataItem item = registeredItems[i];
  400. if (item.name == name)
  401. {
  402. registeredItems.RemoveAt(i);
  403. break;
  404. }
  405. }
  406. DataComponentBase comp = FindDataComponent(name);
  407. if (comp != null)
  408. comp.Dispose();
  409. if (data is DataSet)
  410. {
  411. foreach (DataTable table in (data as DataSet).Tables)
  412. {
  413. UnregisterData(table, name + "." + table.TableName);
  414. }
  415. foreach (DataRelation relation in (data as DataSet).Relations)
  416. {
  417. UnregisterData(relation, name + "." + relation.RelationName);
  418. }
  419. }
  420. }
  421. /// <summary>
  422. /// Re-registers the data registered before.
  423. /// </summary>
  424. /// <remarks>
  425. /// This method is for internal use only.
  426. /// </remarks>
  427. public void ReRegisterData()
  428. {
  429. ReRegisterData(this);
  430. }
  431. /// <summary>
  432. /// Re-registers the data registered before.
  433. /// </summary>
  434. /// <param name="dictionary"></param>
  435. public void ReRegisterData(Dictionary dictionary)
  436. {
  437. // re-register all data items. It is needed after load or "new report" operations
  438. if (registeredItems.Count > 0)
  439. {
  440. DictionaryHelper helper = new DictionaryHelper(dictionary, dictionary.AllObjects, dictionary.Report.AllNamedObjects);
  441. helper.ReRegisterData(registeredItems, false);
  442. }
  443. }
  444. /// <summary>
  445. /// Clears all registered data.
  446. /// </summary>
  447. public void ClearRegisteredData()
  448. {
  449. registeredItems.Clear();
  450. }
  451. /// <summary>
  452. /// Enables or disables relations between data tables.
  453. /// </summary>
  454. /// <remarks>
  455. /// Call this method if you create master-detail report from code. This method enables
  456. /// relation between two data tables which <b>Enabled</b> flag is set to <b>true</b>. Relations
  457. /// whose parent and child tables are disabled, gets disabled too.
  458. /// </remarks>
  459. public void UpdateRelations()
  460. {
  461. foreach (Relation relation in Relations)
  462. {
  463. relation.Enabled = relation.ParentDataSource != null && relation.ParentDataSource.Enabled &&
  464. relation.ChildDataSource != null && relation.ChildDataSource.Enabled;
  465. }
  466. }
  467. /// <summary>
  468. /// Creates unique name for data item such as connection, datasource, relation, parameter or total.
  469. /// </summary>
  470. /// <param name="name">The base name.</param>
  471. /// <returns>The new unique name.</returns>
  472. /// <remarks>
  473. /// Use this method to create unique name of the data item. It is necessary when you create new
  474. /// items in code to avoid conflicts with existing report items.
  475. /// <example>This example show how to add a new parameter:
  476. /// <code>
  477. /// Report report1;
  478. /// Parameter par = new Parameter();
  479. /// par.Name = report1.Dictionary.CreateUniqueName("Parameter");
  480. /// report1.Parameters.Add(par);
  481. /// </code>
  482. /// </example>
  483. /// </remarks>
  484. public string CreateUniqueName(string name)
  485. {
  486. string baseName = name;
  487. int i = 1;
  488. while (FindByName(name) != null || Report.FindObject(name) != null)
  489. {
  490. name = baseName + i.ToString();
  491. i++;
  492. }
  493. return name;
  494. }
  495. /// <summary>
  496. /// Creates unique alias for data item such as connection, datasource or relation.
  497. /// </summary>
  498. /// <param name="alias">The base alias.</param>
  499. /// <returns>The new unique alias.</returns>
  500. /// <remarks>
  501. /// Use this method to create unique alias of the data item. It is necessary when you create new
  502. /// items in code to avoid conflicts with existing report items.
  503. /// <example>This example show how to add a new table:
  504. /// <code>
  505. /// Report report1;
  506. /// DataConnectionBase conn = report1.Dictionary.Connections.FindByName("Connection1");
  507. /// TableDataSource table = new TableDataSource();
  508. /// table.TableName = "Employees";
  509. /// table.Name = report1.Dictionary.CreateUniqueName("EmployeesTable");
  510. /// table.Alias = report1.Dictionary.CreateUniqueAlias("Employees");
  511. /// conn.Tables.Add(table);
  512. /// </code>
  513. /// </example>
  514. /// </remarks>
  515. public string CreateUniqueAlias(string alias)
  516. {
  517. string baseAlias = alias;
  518. int i = 1;
  519. while (FindByAlias(alias) != null)
  520. {
  521. alias = baseAlias + i.ToString();
  522. i++;
  523. }
  524. return alias;
  525. }
  526. /// <summary>
  527. /// Finds a data item such as connection, datasource, relation, parameter or total by its name.
  528. /// </summary>
  529. /// <param name="name">The item's name.</param>
  530. /// <returns>The data item if found; otherwise, <b>null</b>.</returns>
  531. public Base FindByName(string name)
  532. {
  533. foreach (Base c in AllObjects)
  534. {
  535. if (c is DataConnectionBase || c is DataSourceBase || c is Relation ||
  536. (c is Parameter && c.Parent == this) || c is Total || c is CubeSourceBase)
  537. {
  538. // check complete match or match without case sensitivity
  539. if (name == c.Name || name.ToLower() == c.Name.ToLower())
  540. return c;
  541. }
  542. }
  543. return null;
  544. }
  545. /// <summary>
  546. /// Finds a data item such as connection, datasource or relation by its alias.
  547. /// </summary>
  548. /// <param name="alias">The item's alias.</param>
  549. /// <returns>The data item if found; otherwise, <b>null</b>.</returns>
  550. public DataComponentBase FindByAlias(string alias)
  551. {
  552. foreach (Base c in AllObjects)
  553. {
  554. if (c is DataConnectionBase || c is Relation)
  555. {
  556. // check complete match or match without case sensitivity
  557. if (alias == (c as DataComponentBase).Alias || alias.ToLower() == (c as DataComponentBase).Alias.ToLower())
  558. return c as DataComponentBase;
  559. }
  560. else if (c is DataSourceBase)
  561. {
  562. // check complete match or match without case sensitivity
  563. if (alias == (c as DataSourceBase).FullName || alias.ToLower() == (c as DataSourceBase).FullName.ToLower())
  564. return c as DataSourceBase;
  565. }
  566. }
  567. return null;
  568. }
  569. /// <summary>
  570. /// Finds a datasource that matches the specified DataTable.
  571. /// </summary>
  572. /// <param name="table">The <b>DataTable</b> object to check.</param>
  573. /// <returns>The <b>DataSourceBase</b> object if found.</returns>
  574. /// <remarks>
  575. /// This method is for internal use only.
  576. /// </remarks>
  577. public DataSourceBase FindDataTableSource(DataTable table)
  578. {
  579. foreach (DataSourceBase c in DataSources)
  580. {
  581. if (c is TableDataSource && c.Reference == table)
  582. return c;
  583. }
  584. return null;
  585. }
  586. /// <summary>
  587. /// Finds a data component that matches the specified reference name.
  588. /// </summary>
  589. /// <param name="referenceName">The name to check.</param>
  590. /// <returns>The <b>DataComponentBase</b> object if found.</returns>
  591. /// <remarks>
  592. /// This method is for internal use only.
  593. /// </remarks>
  594. public DataComponentBase FindDataComponent(string referenceName)
  595. {
  596. foreach (Base c in AllObjects)
  597. {
  598. DataComponentBase data = c as DataComponentBase;
  599. if (data != null && data.ReferenceName == referenceName)
  600. return data;
  601. }
  602. return null;
  603. }
  604. /// <inheritdoc/>
  605. public override void Serialize(FRWriter writer)
  606. {
  607. writer.ItemName = ClassName;
  608. ObjectCollection childObjects = ChildObjects;
  609. foreach (Base c in childObjects)
  610. {
  611. if (c is Parameter || c is Total || c is CubeSourceBase || (c is DataComponentBase && (c as DataComponentBase).Enabled))
  612. writer.Write(c);
  613. }
  614. }
  615. /// <inheritdoc/>
  616. public override void Deserialize(FRReader reader)
  617. {
  618. base.Deserialize(reader);
  619. ReRegisterData();
  620. }
  621. /// <summary>
  622. /// Saves the dictionary to a stream.
  623. /// </summary>
  624. /// <param name="stream">Stream to save to.</param>
  625. public void Save(Stream stream)
  626. {
  627. using (FRWriter writer = new FRWriter())
  628. {
  629. writer.Write(this);
  630. writer.Save(stream);
  631. }
  632. }
  633. /// <summary>
  634. /// Saves the dictionary to a file.
  635. /// </summary>
  636. /// <param name="fileName">The name of a file to save to.</param>
  637. public void Save(string fileName)
  638. {
  639. using (FileStream f = new FileStream(fileName, FileMode.Create))
  640. {
  641. Save(f);
  642. }
  643. }
  644. /// <summary>
  645. /// Loads the dictionary from a stream.
  646. /// </summary>
  647. /// <param name="stream">The stream to load from.</param>
  648. public void Load(Stream stream)
  649. {
  650. Clear();
  651. using (FRReader reader = new FRReader(Report))
  652. {
  653. reader.Load(stream);
  654. reader.Read(this);
  655. }
  656. }
  657. /// <summary>
  658. /// Loads the dictionary from a file.
  659. /// </summary>
  660. /// <param name="fileName">The name of a file to load from.</param>
  661. public void Load(string fileName)
  662. {
  663. using (FileStream f = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
  664. {
  665. Load(f);
  666. }
  667. }
  668. /// <summary>
  669. /// Merges this dictionary with another <b>Dictionary</b>.
  670. /// </summary>
  671. /// <param name="source">Another dictionary to merge the data from.</param>
  672. public void Merge(Dictionary source)
  673. {
  674. // Report object is needed to handle save/load of dictionary correctly.
  675. // Some dictionary objects (such as relations) may contain references to other objects.
  676. // In order to clone them correctly, we need a parent Report object, because
  677. // reader uses it to fixup references.
  678. using (Report cloneReport = new Report())
  679. {
  680. Dictionary clone = cloneReport.Dictionary;
  681. clone.AssignAll(source, true);
  682. foreach (Base c in clone.ChildObjects)
  683. {
  684. Base my = FindByName(c.Name);
  685. if (my != null)
  686. {
  687. foreach (PageBase page in Report.Pages)
  688. {
  689. if (page is ReportPage)
  690. foreach (BandBase band in (page as ReportPage).Bands)
  691. {
  692. if (band is DataBand && (band as DataBand).DataSource != null && (my.AllObjects.Contains((band as DataBand).DataSource) || (band as DataBand).DataSource == my))
  693. (band as DataBand).DataSource = (DataSourceBase)clone.FindByName((band as DataBand).DataSource.Name);
  694. }
  695. }
  696. my.Dispose();
  697. }
  698. c.Parent = this;
  699. }
  700. source.ReRegisterData(this);
  701. ReRegisterData();
  702. }
  703. }
  704. #endregion
  705. #region IParent Members
  706. /// <inheritdoc/>
  707. public bool CanContain(Base child)
  708. {
  709. return child is DataConnectionBase || child is DataSourceBase || child is Relation || child is Parameter ||
  710. child is Total || child is CubeSourceBase;
  711. }
  712. /// <inheritdoc/>
  713. public void GetChildObjects(ObjectCollection list)
  714. {
  715. foreach (DataConnectionBase c in Connections)
  716. {
  717. list.Add(c);
  718. }
  719. foreach (DataSourceBase c in DataSources)
  720. {
  721. list.Add(c);
  722. }
  723. foreach (Relation c in Relations)
  724. {
  725. list.Add(c);
  726. }
  727. foreach (Parameter c in Parameters)
  728. {
  729. list.Add(c);
  730. }
  731. foreach (Total c in Totals)
  732. {
  733. list.Add(c);
  734. }
  735. foreach (CubeSourceBase c in CubeSources)
  736. {
  737. list.Add(c);
  738. }
  739. }
  740. /// <inheritdoc/>
  741. public void AddChild(Base child)
  742. {
  743. if (child is DataConnectionBase)
  744. Connections.Add(child as DataConnectionBase);
  745. else if (child is DataSourceBase)
  746. DataSources.Add(child as DataSourceBase);
  747. else if (child is Relation)
  748. Relations.Add(child as Relation);
  749. else if (child is Parameter)
  750. Parameters.Add(child as Parameter);
  751. else if (child is Total)
  752. Totals.Add(child as Total);
  753. else if (child is CubeSourceBase)
  754. CubeSources.Add(child as CubeSourceBase);
  755. }
  756. /// <inheritdoc/>
  757. public void RemoveChild(Base child)
  758. {
  759. if (child is DataConnectionBase)
  760. Connections.Remove(child as DataConnectionBase);
  761. else if (child is DataSourceBase)
  762. DataSources.Remove(child as DataSourceBase);
  763. else if (child is Relation)
  764. Relations.Remove(child as Relation);
  765. else if (child is Parameter)
  766. Parameters.Remove(child as Parameter);
  767. else if (child is Total)
  768. Totals.Remove(child as Total);
  769. else if (child is CubeSourceBase)
  770. CubeSources.Remove(child as CubeSourceBase);
  771. }
  772. /// <inheritdoc/>
  773. public int GetChildOrder(Base child)
  774. {
  775. return 0;
  776. }
  777. /// <inheritdoc/>
  778. public void SetChildOrder(Base child, int order)
  779. {
  780. // do nothing
  781. }
  782. /// <inheritdoc/>
  783. public void UpdateLayout(float dx, float dy)
  784. {
  785. // do nothing
  786. }
  787. #endregion
  788. /// <summary>
  789. /// Initializes a new instance of the <see cref="Dictionary"/> class with default settings.
  790. /// </summary>
  791. public Dictionary()
  792. {
  793. connections = new ConnectionCollection(this);
  794. dataSources = new DataSourceCollection(this);
  795. relations = new RelationCollection(this);
  796. parameters = new ParameterCollection(this);
  797. systemVariables = new SystemVariables(this);
  798. totals = new TotalCollection(this);
  799. cubeSources = new CubeSourceCollection(this);
  800. registeredItems = new List<RegDataItem>();
  801. }
  802. /// <summary>
  803. /// Represents the item registered in a dictionary.
  804. /// </summary>
  805. public class RegDataItem
  806. {
  807. /// <summary>
  808. /// Gets the item data.
  809. /// </summary>
  810. public object data;
  811. /// <summary>
  812. /// Gets the item name.
  813. /// </summary>
  814. public string name;
  815. internal RegDataItem(object data, string name)
  816. {
  817. this.data = data;
  818. this.name = name;
  819. }
  820. }
  821. }
  822. }