ContainerObject.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. using FastReport.Utils;
  2. using System;
  3. using System.ComponentModel;
  4. using System.Drawing;
  5. using System.Windows.Forms;
  6. namespace FastReport
  7. {
  8. /// <summary>
  9. /// Container object that may contain child objects.
  10. /// </summary>
  11. public partial class ContainerObject : ReportComponentBase, IParent
  12. {
  13. #region Fields
  14. private ReportComponentCollection objects;
  15. private bool updatingLayout;
  16. private string beforeLayoutEvent;
  17. private string afterLayoutEvent;
  18. private int savedOriginalObjectsCount;
  19. #endregion
  20. #region Properties
  21. /// <summary>
  22. /// Gets the collection of child objects.
  23. /// </summary>
  24. [Browsable(false)]
  25. public ReportComponentCollection Objects
  26. {
  27. get { return objects; }
  28. }
  29. /// <summary>
  30. /// This event occurs before the container layouts its child objects.
  31. /// </summary>
  32. public event EventHandler BeforeLayout;
  33. /// <summary>
  34. /// This event occurs after the child objects layout was finished.
  35. /// </summary>
  36. public event EventHandler AfterLayout;
  37. /// <summary>
  38. /// Gets or sets a script event name that will be fired before the container layouts its child objects.
  39. /// </summary>
  40. [Category("Build")]
  41. public string BeforeLayoutEvent
  42. {
  43. get { return beforeLayoutEvent; }
  44. set { beforeLayoutEvent = value; }
  45. }
  46. /// <summary>
  47. /// Gets or sets a script event name that will be fired after the child objects layout was finished.
  48. /// </summary>
  49. [Category("Build")]
  50. public string AfterLayoutEvent
  51. {
  52. get { return afterLayoutEvent; }
  53. set { afterLayoutEvent = value; }
  54. }
  55. #endregion
  56. #region IParent
  57. /// <inheritdoc/>
  58. public virtual void GetChildObjects(ObjectCollection list)
  59. {
  60. foreach (ReportComponentBase c in objects)
  61. {
  62. list.Add(c);
  63. }
  64. }
  65. /// <inheritdoc/>
  66. public virtual bool CanContain(Base child)
  67. {
  68. return (child is ReportComponentBase);
  69. }
  70. /// <inheritdoc/>
  71. public virtual void AddChild(Base child)
  72. {
  73. if (child is ReportComponentBase)
  74. objects.Add(child as ReportComponentBase);
  75. }
  76. /// <inheritdoc/>
  77. public virtual void RemoveChild(Base child)
  78. {
  79. if (child is ReportComponentBase)
  80. objects.Remove(child as ReportComponentBase);
  81. }
  82. /// <inheritdoc/>
  83. public virtual int GetChildOrder(Base child)
  84. {
  85. return objects.IndexOf(child as ReportComponentBase);
  86. }
  87. /// <inheritdoc/>
  88. public virtual void SetChildOrder(Base child, int order)
  89. {
  90. int oldOrder = child.ZOrder;
  91. if (oldOrder != -1 && order != -1 && oldOrder != order)
  92. {
  93. if (order > objects.Count)
  94. order = objects.Count;
  95. if (oldOrder <= order)
  96. order--;
  97. objects.Remove(child as ReportComponentBase);
  98. objects.Insert(order, child as ReportComponentBase);
  99. }
  100. }
  101. /// <inheritdoc/>
  102. public virtual void UpdateLayout(float dx, float dy)
  103. {
  104. if (updatingLayout)
  105. return;
  106. updatingLayout = true;
  107. try
  108. {
  109. RectangleF remainingBounds = new RectangleF(0, 0, Width, Height);
  110. remainingBounds.Width += dx;
  111. remainingBounds.Height += dy;
  112. foreach (ReportComponentBase c in Objects)
  113. {
  114. if ((c.Anchor & AnchorStyles.Right) != 0)
  115. {
  116. if ((c.Anchor & AnchorStyles.Left) != 0)
  117. c.Width += dx;
  118. else
  119. c.Left += dx;
  120. }
  121. else if ((c.Anchor & AnchorStyles.Left) == 0)
  122. {
  123. c.Left += dx / 2;
  124. }
  125. if ((c.Anchor & AnchorStyles.Bottom) != 0)
  126. {
  127. if ((c.Anchor & AnchorStyles.Top) != 0)
  128. c.Height += dy;
  129. else
  130. c.Top += dy;
  131. }
  132. else if ((c.Anchor & AnchorStyles.Top) == 0)
  133. {
  134. c.Top += dy / 2;
  135. }
  136. switch (c.Dock)
  137. {
  138. case DockStyle.Left:
  139. c.Bounds = new RectangleF(remainingBounds.Left, remainingBounds.Top, c.Width, remainingBounds.Height);
  140. remainingBounds.X += c.Width;
  141. remainingBounds.Width -= c.Width;
  142. break;
  143. case DockStyle.Top:
  144. c.Bounds = new RectangleF(remainingBounds.Left, remainingBounds.Top, remainingBounds.Width, c.Height);
  145. remainingBounds.Y += c.Height;
  146. remainingBounds.Height -= c.Height;
  147. break;
  148. case DockStyle.Right:
  149. c.Bounds = new RectangleF(remainingBounds.Right - c.Width, remainingBounds.Top, c.Width, remainingBounds.Height);
  150. remainingBounds.Width -= c.Width;
  151. break;
  152. case DockStyle.Bottom:
  153. c.Bounds = new RectangleF(remainingBounds.Left, remainingBounds.Bottom - c.Height, remainingBounds.Width, c.Height);
  154. remainingBounds.Height -= c.Height;
  155. break;
  156. case DockStyle.Fill:
  157. c.Bounds = remainingBounds;
  158. remainingBounds.Width = 0;
  159. remainingBounds.Height = 0;
  160. break;
  161. }
  162. }
  163. }
  164. finally
  165. {
  166. updatingLayout = false;
  167. }
  168. }
  169. #endregion
  170. #region Report engine
  171. /// <inheritdoc/>
  172. public override void SaveState()
  173. {
  174. base.SaveState();
  175. savedOriginalObjectsCount = Objects.Count;
  176. SetRunning(true);
  177. SetDesigning(false);
  178. foreach (ReportComponentBase obj in Objects)
  179. {
  180. obj.SaveState();
  181. obj.SetRunning(true);
  182. obj.SetDesigning(false);
  183. obj.OnBeforePrint(EventArgs.Empty);
  184. }
  185. }
  186. /// <inheritdoc/>
  187. public override void RestoreState()
  188. {
  189. base.RestoreState();
  190. while (Objects.Count > savedOriginalObjectsCount)
  191. {
  192. Objects[Objects.Count - 1].Dispose();
  193. }
  194. SetRunning(false);
  195. foreach (ReportComponentBase obj in Objects)
  196. {
  197. obj.OnAfterPrint(EventArgs.Empty);
  198. obj.RestoreState();
  199. obj.SetRunning(false);
  200. }
  201. }
  202. /// <inheritdoc/>
  203. public override void GetData()
  204. {
  205. base.GetData();
  206. var objArray = Objects.ToArray();
  207. foreach (ReportComponentBase obj in objArray)
  208. {
  209. obj.GetData();
  210. obj.OnAfterData();
  211. // break the component if it is of BreakableComponent an has non-empty BreakTo property
  212. if (obj is BreakableComponent && (obj as BreakableComponent).BreakTo != null &&
  213. (obj as BreakableComponent).BreakTo.GetType() == obj.GetType())
  214. (obj as BreakableComponent).Break((obj as BreakableComponent).BreakTo);
  215. }
  216. }
  217. /// <inheritdoc/>
  218. public override float CalcHeight()
  219. {
  220. OnBeforeLayout(EventArgs.Empty);
  221. // sort objects by Top
  222. ReportComponentCollection sortedObjects = Objects.SortByTop();
  223. // calc height of each object
  224. float[] heights = new float[sortedObjects.Count];
  225. for (int i = 0; i < sortedObjects.Count; i++)
  226. {
  227. ReportComponentBase obj = sortedObjects[i];
  228. float height = obj.Height;
  229. if (obj.Visible && (obj.CanGrow || obj.CanShrink))
  230. {
  231. float height1 = obj.CalcHeight();
  232. if ((obj.CanGrow && height1 > height) || (obj.CanShrink && height1 < height))
  233. height = height1;
  234. }
  235. heights[i] = height;
  236. }
  237. // calc shift amounts
  238. float[] shifts = new float[sortedObjects.Count];
  239. for (int i = 0; i < sortedObjects.Count; i++)
  240. {
  241. ReportComponentBase parent = sortedObjects[i];
  242. float shift = heights[i] - parent.Height;
  243. if (shift == 0)
  244. continue;
  245. for (int j = i + 1; j < sortedObjects.Count; j++)
  246. {
  247. ReportComponentBase child = sortedObjects[j];
  248. if (child.ShiftMode == ShiftMode.Never)
  249. continue;
  250. if (child.Top >= parent.Bottom - 1e-4)
  251. {
  252. if (child.ShiftMode == ShiftMode.WhenOverlapped &&
  253. (child.Left > parent.Right - 1e-4 || parent.Left > child.Right - 1e-4))
  254. continue;
  255. float parentShift = shifts[i];
  256. float childShift = shifts[j];
  257. if (shift > 0)
  258. childShift = Math.Max(shift + parentShift, childShift);
  259. else
  260. childShift = Math.Min(shift + parentShift, childShift);
  261. shifts[j] = childShift;
  262. }
  263. }
  264. }
  265. // update location and size of each component, calc max height
  266. float maxHeight = 0;
  267. for (int i = 0; i < sortedObjects.Count; i++)
  268. {
  269. ReportComponentBase obj = sortedObjects[i];
  270. DockStyle saveDock = obj.Dock;
  271. obj.Dock = DockStyle.None;
  272. obj.Height = heights[i];
  273. obj.Top += shifts[i];
  274. if (obj.Visible && obj.Bottom > maxHeight)
  275. maxHeight = obj.Bottom;
  276. obj.Dock = saveDock;
  277. }
  278. // perform grow to bottom
  279. foreach (ReportComponentBase obj in Objects)
  280. {
  281. if (obj.GrowToBottom || obj.Bottom > maxHeight)
  282. obj.Height = maxHeight - obj.Top;
  283. }
  284. OnAfterLayout(EventArgs.Empty);
  285. return maxHeight;
  286. }
  287. /// <summary>
  288. /// This method fires the <b>BeforeLayout</b> event and the script code connected to the <b>BeforeLayoutEvent</b>.
  289. /// </summary>
  290. /// <param name="e">Event data.</param>
  291. public void OnBeforeLayout(EventArgs e)
  292. {
  293. if (BeforeLayout != null)
  294. BeforeLayout(this, e);
  295. InvokeEvent(BeforeLayoutEvent, e);
  296. }
  297. /// <summary>
  298. /// This method fires the <b>AfterLayout</b> event and the script code connected to the <b>AfterLayoutEvent</b>.
  299. /// </summary>
  300. /// <param name="e">Event data.</param>
  301. public void OnAfterLayout(EventArgs e)
  302. {
  303. if (AfterLayout != null)
  304. AfterLayout(this, e);
  305. InvokeEvent(AfterLayoutEvent, e);
  306. }
  307. #endregion
  308. #region Public methods
  309. /// <inheritdoc/>
  310. public override void Assign(Base source)
  311. {
  312. base.Assign(source);
  313. ContainerObject src = source as ContainerObject;
  314. BeforeLayoutEvent = src.BeforeLayoutEvent;
  315. AfterLayoutEvent = src.AfterLayoutEvent;
  316. }
  317. /// <inheritdoc/>
  318. public override void Serialize(FRWriter writer)
  319. {
  320. ContainerObject c = writer.DiffObject as ContainerObject;
  321. base.Serialize(writer);
  322. if (writer.SerializeTo == SerializeTo.Preview)
  323. return;
  324. if (BeforeLayoutEvent != c.BeforeLayoutEvent)
  325. writer.WriteStr("BeforeLayoutEvent", BeforeLayoutEvent);
  326. if (AfterLayoutEvent != c.AfterLayoutEvent)
  327. writer.WriteStr("AfterLayoutEvent", AfterLayoutEvent);
  328. }
  329. /// <inheritdoc/>
  330. public override void Draw(FRPaintEventArgs e)
  331. {
  332. DrawBackground(e);
  333. DrawMarkers(e);
  334. Border.Draw(e, new RectangleF(AbsLeft, AbsTop, Width, Height));
  335. base.Draw(e);
  336. }
  337. #endregion
  338. /// <summary>
  339. /// Initializes a new instance of the <b>ContainerObject</b> class with default settings.
  340. /// </summary>
  341. public ContainerObject()
  342. {
  343. objects = new ReportComponentCollection(this);
  344. beforeLayoutEvent = "";
  345. afterLayoutEvent = "";
  346. }
  347. }
  348. }