ContainerObject.cs 13 KB

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