ReportTreeWindow.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. using FastReport.Controls;
  2. using FastReport.Utils;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Drawing;
  6. using System.Windows.Forms;
  7. namespace FastReport.Design.ToolWindows
  8. {
  9. /// <summary>
  10. /// Represents the "Report Tree" window.
  11. /// </summary>
  12. public class ReportTreeWindow : FilterableToolWindow
  13. {
  14. #region Fields
  15. private Dictionary<Base, TreeNode> objectNodes;
  16. private Panel dragIndicator;
  17. private ToolbarButton btnSync;
  18. #endregion
  19. #region Private Methods
  20. private void UpdateSelection()
  21. {
  22. if (Designer.SelectedObjects == null || Designer.SelectedObjects.Count == 0)
  23. return;
  24. if (objectNodes.ContainsKey(Designer.SelectedObjects[0]))
  25. {
  26. ObjectsToSelectedNodes();
  27. }
  28. }
  29. private void ObjectsToSelectedNodes()
  30. {
  31. var nodes = new List<TreeNode>();
  32. foreach (Base b in Designer.SelectedObjects)
  33. nodes.Add(objectNodes[b]);
  34. tree.SelectedNodes = nodes;
  35. if (btnSync.Checked)
  36. tree.TrackSelection();
  37. }
  38. private void SelectedNodesToObjects()
  39. {
  40. Designer.SelectedObjects.Clear();
  41. foreach (var node in tree.SelectedNodes)
  42. Designer.SelectedObjects.Add(node.Tag as Base);
  43. // activate object's page
  44. if (Designer.SelectedObjects.Count > 0)
  45. {
  46. var c = Designer.SelectedObjects[0];
  47. if (!(c is Report))
  48. Designer.ActiveReportTab.ActivePage = c.Page;
  49. }
  50. Designer.SelectionChanged(this);
  51. }
  52. private void EnumComponents(Base rootComponent, TreeNodeCollection rootNode)
  53. {
  54. string name = rootComponent is Report ?
  55. "Report - " + Designer.ActiveReportTab.ReportName : rootComponent.Name;
  56. TreeNode node = rootNode.Add(name);
  57. node.Tag = rootComponent;
  58. objectNodes[rootComponent] = node;
  59. int imageIndex = rootComponent.GetImageIndex();
  60. if (imageIndex != -1)
  61. {
  62. node.ImageIndex = imageIndex;
  63. node.SelectedImageIndex = imageIndex;
  64. }
  65. if (rootComponent.HasFlag(Flags.CanShowChildrenInReportTree))
  66. {
  67. foreach (Base component in rootComponent.ChildObjects)
  68. EnumComponents(component, node.Nodes);
  69. }
  70. }
  71. private bool CheckChanges(Base rootComponent, TreeNode rootNode)
  72. {
  73. if (rootNode.Tag != rootComponent)
  74. return false;
  75. if (!(rootComponent is Report))
  76. {
  77. if (rootNode.Text != rootComponent.Name)
  78. return false;
  79. }
  80. if (!rootComponent.HasFlag(Flags.CanShowChildrenInReportTree))
  81. return true;
  82. ObjectCollection childObjects = rootComponent.ChildObjects;
  83. if (childObjects.Count != rootNode.Nodes.Count)
  84. return false;
  85. for (int i = 0; i < childObjects.Count; i++)
  86. {
  87. if (!CheckChanges(childObjects[i], rootNode.Nodes[i]))
  88. return false;
  89. }
  90. return true;
  91. }
  92. private void tree_SelectionChanged(object sender, EventArgs e)
  93. {
  94. SelectedNodesToObjects();
  95. }
  96. private void tree_RightMouseButtonClicked(object sender, MouseEventArgs e)
  97. {
  98. var menu = Designer.SelectedObjects[0].GetContextMenu();
  99. menu?.Show(tree, e.Location);
  100. }
  101. private void tree_ItemDrag(object sender, ItemDragEventArgs e)
  102. {
  103. // check if every item can be dragged
  104. var effect = DragDropEffects.Move;
  105. foreach (Base draggedItem in Designer.SelectedObjects)
  106. {
  107. if (draggedItem is ComponentBase &&
  108. (draggedItem.IsAncestor || draggedItem.HasFlag(Flags.CanChangeParent)))
  109. {
  110. // ok
  111. }
  112. else
  113. {
  114. effect = DragDropEffects.None;
  115. break;
  116. }
  117. }
  118. tree.DoDragDrop(e.Item, effect);
  119. }
  120. private void tree_DragOver(object sender, DragEventArgs e)
  121. {
  122. dragIndicator.Hide();
  123. TreeNode targetNode = (tree.GetNodeAt(tree.PointToClient(new Point(e.X, e.Y))));
  124. if (targetNode == null || e.AllowedEffect == DragDropEffects.None)
  125. return;
  126. Base target = targetNode.Tag as Base;
  127. // allowed moves are:
  128. // - target is not dragged
  129. // - target is not child of dragged
  130. // - dragged is not child of parent
  131. // - target can contain dragged, or
  132. // parent of target can contain dragged
  133. int dragPos = 0;
  134. int allow = 0;
  135. foreach (Base dragged in Designer.SelectedObjects)
  136. {
  137. if (dragged == target || target.HasParent(dragged) || dragged.Parent == target)
  138. continue;
  139. bool changeParent = (target as IParent)?.CanContain(dragged) ?? false;
  140. bool changeOrder = (target.Parent as IParent)?.CanContain(dragged) ?? false;
  141. if (changeParent || changeOrder)
  142. {
  143. allow++;
  144. dragPos = changeParent ? targetNode.Bounds.Bottom : targetNode.Bounds.Top;
  145. }
  146. }
  147. if (allow == Designer.SelectedObjects.Count)
  148. {
  149. e.Effect = e.AllowedEffect;
  150. dragIndicator.BackColor = tree.ForeColor;
  151. dragIndicator.SetBounds(tree.Left + targetNode.Bounds.Left, tree.Top + dragPos, targetNode.Bounds.Width, Designer.LogicalToDevice(2));
  152. dragIndicator.Show();
  153. }
  154. }
  155. private void tree_DragDrop(object sender, DragEventArgs e)
  156. {
  157. dragIndicator.Hide();
  158. TreeNode targetNode = tree.GetNodeAt(tree.PointToClient(new Point(e.X, e.Y)));
  159. Base target = targetNode.Tag as Base;
  160. // cases:
  161. // - target can contain dragged. Just change parent.
  162. // - target cannot contain dragged. Change creation order (Z-order).
  163. foreach (Base dragged in Designer.SelectedObjects)
  164. {
  165. if (target is IParent par && par.CanContain(dragged))
  166. {
  167. dragged.Parent = target;
  168. }
  169. else
  170. {
  171. Base parent = target.Parent;
  172. dragged.Parent = parent;
  173. dragged.ZOrder = target.ZOrder;
  174. }
  175. }
  176. // update all designer plugins (this one too)
  177. Designer.SetModified(null, "ChangeParent");
  178. }
  179. private void tree_DragLeave(object sender, EventArgs e)
  180. {
  181. dragIndicator.Hide();
  182. }
  183. private void tree_KeyDown(object sender, KeyEventArgs e)
  184. {
  185. if (e.KeyCode == Keys.Delete)
  186. Designer.cmdDelete.Invoke();
  187. }
  188. private void tree_BeforeLabelEdit(object sender, NodeLabelEditEventArgs e)
  189. {
  190. Base c = e.Node.Tag as Base;
  191. if (c is Report)
  192. e.CancelEdit = true;
  193. }
  194. private void tree_AfterLabelEdit(object sender, NodeLabelEditEventArgs e)
  195. {
  196. if (e.Label != null)
  197. {
  198. Base c = e.Node.Tag as Base;
  199. try
  200. {
  201. c.Name = e.Label;
  202. Designer.SetModified(this, "Change");
  203. }
  204. catch (Exception ex)
  205. {
  206. FRMessageBox.Error(ex.Message);
  207. e.CancelEdit = true;
  208. }
  209. }
  210. }
  211. private void btnSync_Click(object sender, EventArgs e)
  212. {
  213. tree.TrackSelection();
  214. }
  215. #endregion
  216. #region Protected/Public Methods
  217. /// <inheritdoc/>
  218. protected override void UpdateTree()
  219. {
  220. // if there was no changes in the report structure, do nothing
  221. if (Designer.ActiveReport != null && tree.Nodes.Count > 0)
  222. {
  223. if (CheckChanges(Designer.ActiveReport, tree.Nodes[0]))
  224. return;
  225. }
  226. tree.BeginUpdate();
  227. tree.Nodes.Clear();
  228. objectNodes.Clear();
  229. if (Designer.ActiveReport != null)
  230. EnumComponents(Designer.ActiveReport, tree.Nodes);
  231. tree.ExpandAll();
  232. tree.EndUpdate();
  233. }
  234. /// <inheritdoc/>
  235. public override void SelectionChanged()
  236. {
  237. Throttle.Execute(UpdateSelection);
  238. }
  239. /// <inheritdoc/>
  240. public override void UpdateContent()
  241. {
  242. Throttle.Execute(() =>
  243. {
  244. UpdateTree();
  245. UpdateSelection();
  246. #if !WPF
  247. SearchMatches();
  248. #endif
  249. });
  250. }
  251. /// <inheritdoc/>
  252. public override void Localize()
  253. {
  254. base.Localize();
  255. MyRes res = new MyRes("Designer,ToolWindow,ReportTree");
  256. Text = res.Get("");
  257. btnSync.ToolTipText = res.Get("Sync");
  258. }
  259. /// <inheritdoc/>
  260. public override void UpdateDpiDependencies()
  261. {
  262. base.UpdateDpiDependencies();
  263. Image = Designer.GetImage(189);
  264. tree.ImageList = Designer.GetImages();
  265. }
  266. #endregion
  267. /// <summary>
  268. /// Initializes a new instance of the <see cref="ReportTreeWindow"/> class with default settings.
  269. /// </summary>
  270. /// <param name="designer">The report designer.</param>
  271. public ReportTreeWindow(Designer designer) : base(designer)
  272. {
  273. Name = "ReportTreeWindow";
  274. objectNodes = new Dictionary<Base, TreeNode>();
  275. tree.LabelEdit = true;
  276. tree.ShowRootLines = false;
  277. tree.AllowDrop = true;
  278. tree.SelectionChanged += tree_SelectionChanged;
  279. tree.RightMouseButtonClicked += tree_RightMouseButtonClicked;
  280. tree.ItemDrag += tree_ItemDrag;
  281. tree.DragOver += tree_DragOver;
  282. tree.DragDrop += tree_DragDrop;
  283. tree.DragLeave += tree_DragLeave;
  284. tree.KeyDown += tree_KeyDown;
  285. tree.BeforeLabelEdit += tree_BeforeLabelEdit;
  286. tree.AfterLabelEdit += tree_AfterLabelEdit;
  287. btnSync = AddButton(81, btnSync_Click);
  288. btnSync.CheckOnClick = true;
  289. toolbar.AddItems(btnSync);
  290. dragIndicator = new Panel();
  291. dragIndicator.Visible = false;
  292. Controls.Add(dragIndicator);
  293. Controls.SetChildIndex(dragIndicator, 0);
  294. Localize();
  295. UpdateDpiDependencies();
  296. }
  297. }
  298. }