using System; using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; using FastReport.Utils; namespace FastReport.Forms { #if !COMMUNITY public partial class ExportsOptionsEditorForm : BaseDialogForm { #region Helper functions private void Init() { tvExportsMenu.BeginUpdate(); tvExportsMenu.Nodes.Clear(); List menu = new List(); foreach (var node in options.ExportsMenu.Nodes) menu.Add(node); options.CloudMenu.Enabled = false; foreach (var node in options.CloudMenu.Nodes) { if (node.Enabled) { options.CloudMenu.Enabled = true; break; } } menu.Add(options.CloudMenu); options.MessengerMenu.Enabled = false; foreach (var node in options.MessengerMenu.Nodes) { if (node.Enabled) { options.MessengerMenu.Enabled = true; break; } } //menu.Add(options.MessengerMenu); fillExportsMenu(menu, tvExportsMenu.Nodes); tvExportsMenu.ExpandAll(); tvExportsMenu.EndUpdate(); } private TreeNode createTreeNode(ExportsOptions.ExportsTreeNode node) { TreeNode newNode = new TreeNode(node.ToString()); // Using out of range index because there is no other way to draw node without image newNode.ImageIndex = node.ImageIndex == -1 ? 1000 : node.ImageIndex; newNode.SelectedImageIndex = newNode.ImageIndex; newNode.Tag = node; setChecked(newNode, node.Enabled); return newNode; } private void fillExportsMenu(IList nodes, TreeNodeCollection currentTreeLayer) { for (int i = 0; i < nodes.Count; ++i) { currentTreeLayer.Add(createTreeNode(nodes[i])); if (nodes[i].Nodes.Count > 0) { fillExportsMenu(nodes[i].Nodes, currentTreeLayer[i].Nodes); } } } private bool isCategory(TreeNode node) { return (node.Tag as ExportsOptions.ExportsTreeNode).IsCategory; } private bool isDraggable(TreeNode node) { return (node.Tag as ExportsOptions.ExportsTreeNode).Root == ExportsOptions.GetInstance().ExportsMenu; } private bool containsNode(TreeNode targetNode, TreeNode draggedNode) { while (targetNode != null) { if (targetNode.Equals(draggedNode)) { return true; } targetNode = targetNode.Parent; } return false; } private bool arePathsEqual(List lhs, List rhs) { if (lhs == null || rhs == null || lhs.Count != rhs.Count) { return false; } for (int i = 0; i < lhs.Count; ++i) { if (lhs[i] != rhs[i]) { return false; } } return true; } private List getNodePath(TreeNode node) { List res = new List(); while (node != null) { res.Insert(0, node.Index); node = node.Parent; } return res; } private InsertionPosition getInsertionPosition(TreeNode targetNode, Point cursorPoint) { int offsetY = cursorPoint.Y - targetNode.Bounds.Y; if (isCategory(targetNode)) { if (offsetY < targetNode.Bounds.Height / 3) { return InsertionPosition.Top; } else if (offsetY < (2 * targetNode.Bounds.Height) / 3) { return InsertionPosition.Inside; } else { return InsertionPosition.Bottom; } } else { if (offsetY < targetNode.Bounds.Height / 2) { return InsertionPosition.Top; } else { return InsertionPosition.Bottom; } } } private void drawInsertionLine(InsertionPosition insertionPosition, List treeNodePath) { tvExportsMenu.Refresh(); using (Graphics g = tvExportsMenu.CreateGraphics()) { if (insertionPosition == InsertionPosition.Inside) { return; } TreeNode treeNode = null; TreeNodeCollection nodes = tvExportsMenu.Nodes; foreach (int index in treeNodePath) { treeNode = nodes[index]; nodes = treeNode.Nodes; } if (treeNode != null) { int lineStartX = treeNode.Bounds.X - 50; int lineEndX = tvExportsMenu.Bounds.Width; int lineY = treeNode.Bounds.Y; if (insertionPosition == InsertionPosition.Bottom) { lineY += treeNode.Bounds.Height; } using (Pen pen = new Pen(Brushes.Black, 2)) { g.DrawLine(pen, new Point(lineStartX, lineY), new Point(lineEndX, lineY)); } } } } private void passChanges(TreeNodeCollection tvNodes, ExportsOptions.ExportsTreeNode.ExportsTreeNodeCollection menuNodes) { foreach (TreeNode node in tvNodes) { ExportsOptions.ExportsTreeNode menuNode = node.Tag as ExportsOptions.ExportsTreeNode; menuNode.Enabled = node.Checked; menuNode.Nodes.Clear(); menuNodes.Add(menuNode); if (node.Nodes.Count > 0) { passChanges(node.Nodes, menuNode.Nodes); } } } private void passChanges(TreeNodeCollection tvNodes) { foreach (TreeNode node in tvNodes) { ExportsOptions.ExportsTreeNode menuNode = node.Tag as ExportsOptions.ExportsTreeNode; if (menuNode.Name == "Cloud") { options.CloudMenu.Enabled = node.Checked; options.CloudMenu.Nodes.Clear(); passChanges(node.Nodes, menuNode.Nodes); } else if (menuNode.Name == "Messengers") { options.MessengerMenu.Enabled = node.Checked; options.MessengerMenu.Nodes.Clear(); passChanges(node.Nodes, menuNode.Nodes); } else { menuNode.Enabled = node.Checked; menuNode.Nodes.Clear(); options.ExportsMenu.Nodes.Add(menuNode); if (node.Nodes.Count > 0) { passChanges(node.Nodes, menuNode.Nodes); } } } } private bool isSingleChecked(TreeNode testedNode) { if (testedNode.Parent != null) { foreach (TreeNode node in testedNode.Parent.Nodes) { if (node != testedNode && node.Checked) { return false; } } return true; } return false; } // Because seting Checked property raises AfterCheck event private void setChecked(TreeNode node, bool isChecked) { tvExportsMenu.AfterCheck -= tvExportsMenu_AfterCheck; node.Checked = isChecked; tvExportsMenu.AfterCheck += tvExportsMenu_AfterCheck; } private void checkAllChilds(TreeNode node, bool isChecked) { Queue queue = new Queue(); queue.Enqueue(node); while (queue.Count > 0) { TreeNode currentNode = queue.Dequeue(); setChecked(currentNode, isChecked); foreach (TreeNode item in currentNode.Nodes) { queue.Enqueue(item); } } } #endregion private enum InsertionPosition { Top, Inside, Bottom } private ExportsOptions options = ExportsOptions.GetInstance(); private InsertionPosition currentInsertionPosition; private List prevNodePath; /// /// Editor for rearrangement Exports Menu elements /// public ExportsOptionsEditorForm() { InitializeComponent(); Localize(); Init(); UIUtils.CheckRTL(this); UpdateDpiDependencies(); } /// public override void UpdateDpiDependencies() { base.UpdateDpiDependencies(); tvExportsMenu.ImageList = this.GetImages(); } /// public override void Localize() { base.Localize(); MyRes res = new MyRes("Export,Editor"); this.Text = res.Get(""); gbExportsMenu.Text = res.Get("ExportsMenu"); btnDefaultSettings.Text = res.Get("DefaultMenu"); } private void tvExportsMenu_ItemDrag(object sender, ItemDragEventArgs e) { DoDragDrop(e.Item, DragDropEffects.Move); } private void tvExportsMenu_DragEnter(object sender, DragEventArgs e) { if (e.Data.GetDataPresent(typeof(TreeNode)) && isDraggable(e.Data.GetData(typeof(TreeNode)) as TreeNode)) { e.Effect = e.AllowedEffect; } else { e.Effect = DragDropEffects.None; } } private void tvExportsMenu_DragOver(object sender, DragEventArgs e) { Point point = tvExportsMenu.PointToClient(new Point(e.X, e.Y)); TreeNode targetNode = tvExportsMenu.GetNodeAt(point) as TreeNode; TreeNode draggedNode = e.Data.GetData(typeof(TreeNode)) as TreeNode; if (targetNode != null && !containsNode(targetNode, draggedNode) && isDraggable(draggedNode) && isDraggable(targetNode)) { e.Effect = DragDropEffects.Move; List nodePath = getNodePath(targetNode); InsertionPosition insertionPosition = getInsertionPosition(targetNode, point); if (arePathsEqual(nodePath, prevNodePath) && insertionPosition == currentInsertionPosition) { return; } currentInsertionPosition = insertionPosition; prevNodePath = nodePath; drawInsertionLine(insertionPosition, nodePath); } else { e.Effect = DragDropEffects.None; tvExportsMenu.Refresh(); } } private void tvExportsMenu_DragDrop(object sender, DragEventArgs e) { Point targetPoint = tvExportsMenu.PointToClient(new Point(e.X, e.Y)); TreeNode targetNode = tvExportsMenu.GetNodeAt(targetPoint); TreeNode draggedNode = (TreeNode)e.Data.GetData(typeof(TreeNode)); if (targetNode == null) { draggedNode.Remove(); tvExportsMenu.Nodes.Add(draggedNode); } else if (!containsNode(targetNode, draggedNode)) { if (e.Effect == DragDropEffects.Move) { if (draggedNode.Checked == true && isSingleChecked(draggedNode)) { setChecked(draggedNode.Parent, false); } draggedNode.Remove(); TreeNodeCollection nodes = targetNode.Parent != null ? targetNode.Parent.Nodes : tvExportsMenu.Nodes; switch (currentInsertionPosition) { case InsertionPosition.Top: nodes.Insert(targetNode.Index, draggedNode); break; case InsertionPosition.Inside: targetNode.Nodes.Add(draggedNode); break; case InsertionPosition.Bottom: nodes.Insert(targetNode.Index + 1, draggedNode); break; } if (draggedNode.Checked == true && isSingleChecked(draggedNode)) { setChecked(draggedNode.Parent, true); } } targetNode.Expand(); } } private void btnOk_Click(object sender, EventArgs e) { options.ExportsMenu.Nodes.Clear(); passChanges(tvExportsMenu.Nodes); options.SaveState(); } private void btnDefaultSettings_Click(object sender, EventArgs e) { options.ResetToDefault(); Init(); } private void tvExportsMenu_AfterCheck(object sender, TreeViewEventArgs e) { if (e.Node.Checked) { TreeNode node = e.Node; while (node.Parent != null) { node = node.Parent; setChecked(node, true); } } else { if (isSingleChecked(e.Node)) { setChecked(e.Node.Parent, false); } } checkAllChilds(e.Node, e.Node.Checked); } } #endif }