using FastReport.Controls;
using FastReport.Data;
using FastReport.Forms;
using FastReport.Utils;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
namespace FastReport.Design.ToolWindows
{
///
/// Represents the "Data Dictionary" window.
///
public class DictionaryWindow : FilterableToolWindow
{
#region Fields
private ToolbarDropDownButton btnActions;
private ToolbarButton btnEdit;
private ToolbarButton btnDelete;
private ToolbarButton btnView;
private ContextMenuItem miNew;
private ContextMenuItem miOpen;
private ContextMenuItem miMerge;
private ContextMenuItem miSave;
private ContextMenuItem miChooseData;
private ContextMenuItem miSortDataSources;
private ContextMenuItem miUploadDataSource;
private ContextMenuItem miNewDataSource;
private ContextMenuItem miNewRelation;
private ContextMenuItem miNewParameter;
private ContextMenuItem miNewTotal;
private ContextMenuItem miNewCalculatedColumn;
private ContextMenuItem miCopyDataSource;
private ContextMenuBase mnuContext;
private ContextMenuItem miSortDataSources1;
private ContextMenuItem miUploadDataSource1;
private ContextMenuItem miNewDataSource1;
private ContextMenuItem miNewParameter1;
private ContextMenuItem miNewTotal1;
private ContextMenuItem miNewCalculatedColumn1;
private ContextMenuItem miRename;
private ContextMenuItem miEdit;
private ContextMenuItem miDelete;
private ContextMenuItem miDeleteAlias;
private ContextMenuItem miView;
private ContextMenuItem miViewJson;
private ContextMenuItem miSortDataFields;
private Panel dragIndicator;
private Splitter splitter;
private DescriptionControl lblDescription;
private Report report;
private List expandedNodes;
private bool updating;
private static DraggedItemCollection draggedItems = new DraggedItemCollection();
#endregion
#region Properties
private bool IsDataComponent
{
get { return tree.SelectedNode != null && tree.SelectedNode.Tag is DataComponentBase; }
}
private bool IsVariable
{
get
{
return tree.SelectedNode != null && tree.SelectedNode.Tag is Parameter &&
!(tree.SelectedNode.Parent.Tag is SystemVariables);
}
}
private bool IsTotal
{
get { return tree.SelectedNode != null && tree.SelectedNode.Tag is Total; }
}
private bool IsConnection
{
get { return tree.SelectedNode != null && tree.SelectedNode.Tag is DataConnectionBase; }
}
private bool IsTable
{
get { return tree.SelectedNode != null && tree.SelectedNode.Tag is DataSourceBase; }
}
private bool IsJsonTable
{
get { return tree.SelectedNode != null && tree.SelectedNode.Tag is FastReport.Data.JsonConnection.JsonTableDataSource; }
}
private bool IsRelation
{
get { return tree.SelectedNode != null && tree.SelectedNode.Tag is Relation; }
}
private bool IsEditableColumn
{
get
{
TreeNode node = tree.SelectedNode;
bool result = node != null && node.Tag is Column;
if (result)
{
// check if column belongs to the datasource, not relation.
while (node != null)
{
if (node.Tag is Relation)
{
result = false;
break;
}
else if (node.Tag is DataSourceBase)
break;
node = node.Parent;
}
}
return result;
}
}
private bool IsCube
{
get { return tree.SelectedNode != null && tree.SelectedNode.Tag is CubeSourceBase; }
}
private bool IsDataSources
{
get { return tree.SelectedNode != null && tree.SelectedNode.Tag == report.Dictionary.DataSources; }
}
private bool IsVariables
{
get { return tree.SelectedNode != null && tree.SelectedNode.Tag == report.Dictionary.Parameters; }
}
private bool IsSystemVariables
{
get { return tree.SelectedNode != null && tree.SelectedNode.Tag == report.Dictionary.SystemVariables; }
}
private bool IsTotals
{
get { return tree.SelectedNode != null && tree.SelectedNode.Tag == report.Dictionary.Totals; }
}
private bool IsCubeSources
{
get { return tree.SelectedNode != null && tree.SelectedNode.Tag == report.Dictionary.CubeSources; }
}
private bool CanEdit
{
get
{
return (IsDataComponent || IsVariable || IsTotal) &&
!Designer.Restrictions.DontEditData &&
(tree.SelectedNode.Tag as Base).HasFlag(Flags.CanEdit) &&
!(tree.SelectedNode.Tag as Base).HasRestriction(Restrictions.DontEdit);
}
}
private bool CanDelete
{
get
{
return (IsDataComponent || IsVariable || IsTotal) &&
!Designer.Restrictions.DontEditData &&
(tree.SelectedNode.Tag as Base).HasFlag(Flags.CanDelete) &&
!(tree.SelectedNode.Tag as Base).HasRestriction(Restrictions.DontDelete);
}
}
private bool CanCreateCalculatedColumn
{
get
{
return tree.SelectedNode != null && tree.SelectedNode.Tag is DataSourceBase;
}
}
private bool IsAliased
{
get
{
return tree.SelectedNode != null && tree.SelectedNode.Tag is DataComponentBase &&
(tree.SelectedNode.Tag as DataComponentBase).IsAliased;
}
}
#endregion
#region Private Methods
private TreeNode FindNode(TreeNodeCollection parent, string text)
{
foreach (TreeNode node in parent)
{
if (node.Text == text)
return node;
}
return null;
}
private void NavigateTo(string path)
{
string[] parts = path.Split('.');
TreeNodeCollection parent = tree.Nodes;
TreeNode node = null;
foreach (string part in parts)
{
node = FindNode(parent, part);
if (node == null)
break;
node.Expand();
parent = node.Nodes;
}
tree.SelectedNode = node;
}
private void GetExpandedNodes(TreeNodeCollection nodes)
{
foreach (TreeNode node in nodes)
{
if (node.IsExpanded)
expandedNodes.Add(node.FullPath);
GetExpandedNodes(node.Nodes);
}
}
private bool CompareNodes(TreeNodeCollection fromNodes, TreeNodeCollection toNodes)
{
if (fromNodes.Count != toNodes.Count)
return false;
for (int i = 0; i < fromNodes.Count; i++)
{
if (fromNodes[i].Text != toNodes[i].Text || fromNodes[i].ImageIndex != toNodes[i].ImageIndex)
return false;
toNodes[i].Tag = fromNodes[i].Tag;
if (!CompareNodes(fromNodes[i].Nodes, toNodes[i].Nodes))
return false;
}
return true;
}
private void CopyNodes(TreeNodeCollection fromNodes, TreeNodeCollection toNodes)
{
foreach (TreeNode fromNode in fromNodes)
{
TreeNode toNode = toNodes.Add(fromNode.Text);
toNode.Tag = fromNode.Tag;
toNode.ImageIndex = fromNode.ImageIndex;
toNode.SelectedImageIndex = fromNode.SelectedImageIndex;
CopyNodes(fromNode.Nodes, toNode.Nodes);
if (expandedNodes.Contains(fromNode.FullPath))
toNode.Expand();
}
}
protected override void UpdateTree()
{
expandedNodes.Clear();
GetExpandedNodes(tree.Nodes);
TreeView buffer = new TreeView();
if (report != null)
{
bool canShowData = report.Dictionary.Connections.Count > 0;
foreach (DataSourceBase data in report.Dictionary.DataSources)
{
if (data.Enabled)
{
canShowData = true;
break;
}
}
bool canShowCube = report.Dictionary.CubeSources.Count > 0;
TreeNode rootNode = null;
if (canShowData)
{
rootNode = buffer.Nodes.Add(Res.Get("Designer,ToolWindow,Dictionary,DataSources"));
rootNode.Tag = report.Dictionary.DataSources;
rootNode.ImageIndex = 53;
rootNode.SelectedImageIndex = rootNode.ImageIndex;
DataTreeHelper.CreateDataTree(report.Dictionary, rootNode.Nodes, true, true, true, true);
}
// system variables
rootNode = buffer.Nodes.Add(Res.Get("Designer,ToolWindow,Dictionary,SystemVariables"));
rootNode.Tag = report.Dictionary.SystemVariables;
rootNode.ImageIndex = 60;
rootNode.SelectedImageIndex = rootNode.ImageIndex;
DataTreeHelper.CreateVariablesTree(report.Dictionary.SystemVariables, rootNode.Nodes);
// totals
rootNode = buffer.Nodes.Add(Res.Get("Designer,ToolWindow,Dictionary,Totals"));
rootNode.Tag = report.Dictionary.Totals;
rootNode.ImageIndex = 132;
rootNode.SelectedImageIndex = rootNode.ImageIndex;
DataTreeHelper.CreateTotalsTree(report.Dictionary.Totals, rootNode.Nodes);
// parameters
rootNode = buffer.Nodes.Add(Res.Get("Designer,ToolWindow,Dictionary,Parameters"));
rootNode.Tag = report.Dictionary.Parameters;
rootNode.ImageIndex = 234;
rootNode.SelectedImageIndex = rootNode.ImageIndex;
DataTreeHelper.CreateParametersTree(report.Dictionary.Parameters, rootNode.Nodes);
// functions
rootNode = buffer.Nodes.Add(Res.Get("Designer,ToolWindow,Dictionary,Functions"));
rootNode.ImageIndex = 52;
rootNode.SelectedImageIndex = rootNode.ImageIndex;
DataTreeHelper.CreateFunctionsTree(report, rootNode.Nodes);
if (canShowCube)
{
rootNode = buffer.Nodes.Add(Res.Get("Designer,ToolWindow,Dictionary,CubeSources"));
rootNode.Tag = report.Dictionary.CubeSources;
rootNode.ImageIndex = 248;
rootNode.SelectedImageIndex = rootNode.ImageIndex;
DataTreeHelper.CreateCubeTree(report.Dictionary, rootNode.Nodes, false);
}
}
if (!CompareNodes(buffer.Nodes, tree.Nodes))
{
tree.BeginUpdate();
tree.Nodes.Clear();
CopyNodes(buffer.Nodes, tree.Nodes);
tree.EndUpdate();
}
buffer.Dispose();
UpdateControls();
}
private void Change()
{
Designer.SetModified(this, "EditData");
}
private void UpdateControls()
{
btnEdit.Enabled = CanEdit;
btnDelete.Enabled = CanDelete;
btnView.Enabled = IsTable && !IsJsonTable;
}
private void miNew_Click(object sender, EventArgs e)
{
report.Dictionary.Clear();
report.Dictionary.ReRegisterData();
UpdateTree();
Change();
#if !WPF
SearchMatches();
#endif
}
private void miOpen_Click(object sender, EventArgs e)
{
using (OpenFileDialog dialog = new OpenFileDialog())
{
dialog.Filter = Res.Get("FileFilters,Dictionary");
if (dialog.ShowDialog() == DialogResult.OK)
{
report.Dictionary.Load(dialog.FileName);
UpdateTree();
Change();
#if !WPF
SearchMatches();
#endif
}
}
}
private void miSave_Click(object sender, EventArgs e)
{
using (SaveFileDialog dialog = new SaveFileDialog())
{
dialog.Filter = Res.Get("FileFilters,Dictionary");
dialog.DefaultExt = "frd";
dialog.FileName = "Dictionary.frd";
if (dialog.ShowDialog() == DialogResult.OK)
report.Dictionary.Save(dialog.FileName);
}
}
private void miMerge_Click(object sender, EventArgs e)
{
using (OpenFileDialog dialog = new OpenFileDialog())
{
dialog.Filter = Res.Get("FileFilters,Dictionary");
if (dialog.ShowDialog() == DialogResult.OK)
{
Dictionary dict = new Dictionary();
dict.SetReport(report);
dict.Load(dialog.FileName);
foreach (Base obj in dict.AllObjects)
{
obj.SetReport(report);
}
report.Dictionary.Merge(dict);
UpdateTree();
Change();
#if !WPF
SearchMatches();
#endif
}
}
}
private void btnActions_DropDownOpening(object sender, EventArgs e)
{
miNew.Enabled = Designer.cmdChooseData.Enabled;
miOpen.Enabled = Designer.cmdChooseData.Enabled;
miMerge.Enabled = Designer.cmdChooseData.Enabled;
miSave.Enabled = Designer.cmdChooseData.Enabled;
miChooseData.Enabled = Designer.cmdChooseData.Enabled;
miSortDataSources.Enabled = Designer.cmdSortDataSources.Enabled;
miUploadDataSource.Enabled = IsConnection;
miNewDataSource.Enabled = Designer.cmdAddData.Enabled;
miNewRelation.Enabled = Designer.cmdChooseData.Enabled;
miNewParameter.Enabled = Designer.cmdChooseData.Enabled;
miNewTotal.Enabled = Designer.cmdChooseData.Enabled;
miNewCalculatedColumn.Enabled = Designer.cmdChooseData.Enabled && CanCreateCalculatedColumn;
}
private void mnuContext_Opening(object sender, CancelEventArgs e)
{
mnuContext.Clear();
if (!Designer.cmdChooseData.Enabled)
{
e.Cancel = true;
return;
}
if (IsDataSources || IsConnection)
{
if (Designer.cmdAddData.Enabled)
mnuContext.AddItem(miNewDataSource1);
if (Designer.cmdSortDataSources.Enabled)
mnuContext.AddItem(miSortDataSources1);
if (IsConnection)
{
mnuContext.AddItem(miCopyDataSource);
if (!string.IsNullOrEmpty((tree.SelectedNode.Tag as DataConnectionBase).CloudId))
miUploadDataSource.Text = Res.Get("Designer,ToolWindow,Dictionary,UploadChangesDataSource");
else
miUploadDataSource.Text = Res.Get("Designer,ToolWindow,Dictionary,UploadDataSource");
mnuContext.AddItem(miUploadDataSource1);
}
}
else if (IsVariables || IsVariable)
mnuContext.AddItem(miNewParameter1);
else if (IsTotals || IsTotal)
mnuContext.AddItem(miNewTotal1);
else if (CanCreateCalculatedColumn)
{
mnuContext.AddItem(miNewCalculatedColumn1);
miNewCalculatedColumn.Enabled = true;
}
if (CanEdit)
mnuContext.AddItem(miEdit);
if (IsTable || IsEditableColumn || IsVariable || IsTotal)
mnuContext.AddItem(miRename);
if (CanDelete)
mnuContext.AddItem(miDelete);
if (IsAliased)
mnuContext.AddItem(miDeleteAlias);
if (IsTable || IsJsonTable)
{
mnuContext.AddItem(IsJsonTable ? miViewJson : miView);
DataSourceBase data = tree.SelectedNode.Tag as DataSourceBase;
if (data != null && data.Columns.Count > 1)
{
mnuContext.AddItem(miSortDataFields);
}
}
// .Net: update menu item images
mnuContext.ImageList = Designer.GetImages();
e.Cancel = mnuContext.IsEmpty;
}
private void miNewRelation_Click(object sender, EventArgs e)
{
Relation relation = new Relation();
report.Dictionary.Relations.Add(relation);
using (RelationEditorForm form = new RelationEditorForm(relation))
{
if (form.ShowDialog() == DialogResult.OK)
{
relation.Name = report.Dictionary.CreateUniqueName(relation.ParentDataSource.Name + "_" +
relation.ChildDataSource.Name);
UpdateTree();
Change();
#if !WPF
SearchMatches();
#endif
}
else
relation.Dispose();
}
}
private void miNewCalculatedColumn_Click(object sender, EventArgs e)
{
DataSourceBase data = tree.SelectedNode.Tag as DataSourceBase;
Column c = new Column();
c.Name = data.Columns.CreateUniqueName("Column");
c.Alias = data.Columns.CreateUniqueAlias(c.Alias);
c.Calculated = true;
data.Columns.Add(c);
UpdateTree();
string navigatePath = Res.Get("Designer,ToolWindow,Dictionary,DataSources");
if (data.Parent is DataConnectionBase)
navigatePath += "." + data.Parent.Name + "." + data.Alias;
else
navigatePath += GetPath(data);
navigatePath += "." + c.Alias;
NavigateTo(navigatePath);
Change();
#if !WPF
SearchMatches();
#endif
}
private string GetPath(Base data)
{
if (data == null || data.Name == "")
return "";
if (data.Parent is DataConnectionBase && data.Parent.Parent == null)
return data.Parent.Alias;
else
return GetPath(data.Parent) + "." + data.Name;
}
private void miNewParameter_Click(object sender, EventArgs e)
{
Parameter p = new Parameter();
ParameterCollection parent = null;
if (IsVariable)
parent = (tree.SelectedNode.Tag as Parameter).Parameters;
else
parent = report.Dictionary.Parameters;
p.Name = parent.CreateUniqueName("Parameter");
parent.Add(p);
UpdateTree();
NavigateTo(Res.Get("Designer,ToolWindow,Dictionary,Parameters") + "." + p.FullName);
Change();
#if !WPF
SearchMatches();
#endif
}
private void miNewTotal_Click(object sender, EventArgs e)
{
using (TotalEditorForm form = new TotalEditorForm(Designer))
{
if (form.ShowDialog() == DialogResult.OK)
{
report.Dictionary.Totals.Add(form.Total);
UpdateTree();
NavigateTo(Res.Get("Designer,ToolWindow,Dictionary,Totals") + "." + form.Total.Name);
Change();
#if !WPF
SearchMatches();
#endif
}
}
}
private void miRename_Click(object sender, EventArgs e)
{
if (tree.SelectedNode == null)
return;
tree.SelectedNode.BeginEdit();
}
private void miEdit_Click(object sender, EventArgs e)
{
if (!CanEdit)
return;
IHasEditor c = tree.SelectedNode.Tag as IHasEditor;
if (c != null && c.InvokeEditor())
{
UpdateTree();
Change();
#if !WPF
SearchMatches();
#endif
}
}
private void miDelete_Click(object sender, EventArgs e)
{
TreeNode parentNode = tree.SelectedNode?.Parent;
if (parentNode == null)
return;
int index = parentNode.Nodes.IndexOf(tree.SelectedNode);
for (int i = 0; i < tree.SelectedNodes.Count; i++)
{
if (CanDelete)
{
(tree.SelectedNode.Tag as Base).Delete();
tree.SelectedNode.Remove();
tree.SelectedNodes.RemoveAt(0);
i--;
}
}
index = Math.Min(index, parentNode.Nodes.Count - 1);
tree.SelectedNode = index >= 0 ? parentNode.Nodes[index] : null;
Change();
}
private void miDeleteAlias_Click(object sender, EventArgs e)
{
if (!IsAliased)
return;
DataComponentBase c = tree.SelectedNode.Tag as DataComponentBase;
c.Alias = c.Name;
tree.SelectedNode.Text = c.Name;
Change();
}
private void miView_Click(object sender, EventArgs e)
{
if (!IsTable)
return;
DataSourceBase data = tree.SelectedNode.Tag as DataSourceBase;
if (data == null)
return;
try
{
data.Init();
}
catch (Exception ex)
{
FRMessageBox.Error(ex.Message);
return;
}
object dataSource = null;
if (data is TableDataSource)
{
dataSource = (data as TableDataSource).Table;
}
else
dataSource = data.Rows;
if (dataSource == null)
return;
using (DataViewForm form = new DataViewForm(data))
{
form.ShowDialog();
}
}
private void miViewJson_Click(object sender, EventArgs e)
{
if (!IsJsonTable)
return;
Data.JsonConnection.JsonTableDataSource data = tree.SelectedNode.Tag as Data.JsonConnection.JsonTableDataSource;
if (data == null)
return;
try
{
data.Init();
}
catch (Exception ex)
{
FRMessageBox.Error(ex.Message);
return;
}
using (JsonEditorForm jsonEditorForm = new JsonEditorForm())
{
StringBuilder sb = new StringBuilder();
data.Json.WriteTo(sb, 2);
jsonEditorForm.JsonText = sb.ToString();
jsonEditorForm.SetToReadOnly();
jsonEditorForm.ShowDialog();
}
}
private void miUploadDataSource_Click(object sender, EventArgs e)
{
if (tree.SelectedNode.Tag is DataConnectionBase data)
CloudCommands.UploadDataConnection(data);
}
private void miCopyDataSource_Click(object sender, EventArgs e)
{
if (tree.SelectedNode.Tag is DataConnectionBase)
{
DataConnectionBase data = tree.SelectedNode.Tag as DataConnectionBase;
data.Clone();
}
Change();
UpdateTree();
Refresh();
//Designer.SetModified();
#if !WPF
SearchMatches();
#endif
}
private void miSortDataFields_Click(object sender, EventArgs e)
{
if (!IsTable)
return;
TableDataSource data = tree.SelectedNode.Tag as TableDataSource;
if (data == null)
return;
if (data.Columns.Count > 1)
{
data.Columns.Sort();
UpdateTree();
Change();
#if !WPF
SearchMatches();
#endif
}
}
private void tree_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.F2)
miRename_Click(this, null);
else if (e.KeyCode == Keys.Delete)
miDelete_Click(this, null);
}
private void tree_SelectionChanged(object sender, EventArgs e)
{
if (updating)
return;
Designer.SelectedObjects.Clear();
foreach (var node in tree.SelectedNodes)
{
if (node.Tag is Base c)
Designer.SelectedObjects.Add(c);
}
Designer.SelectionChanged(this);
UpdateControls();
object selected = tree.SelectedNode?.Tag;
bool descrVisible = selected is MethodInfo || selected is SystemVariable;
splitter.Visible = descrVisible;
lblDescription.Visible = descrVisible;
if (descrVisible)
lblDescription.ShowDescription(report, selected);
}
private void tree_RightMouseButtonClicked(object sender, MouseEventArgs e)
{
mnuContext.Show(tree, e.Location);
}
private void tree_BeforeLabelEdit(object sender, NodeLabelEditEventArgs e)
{
bool canEdit = (IsTable || IsEditableColumn || IsVariable || IsTotal) &&
!Designer.Restrictions.DontEditData &&
!(tree.SelectedNode.Tag as Base).HasRestriction(Restrictions.DontModify);
if (!canEdit)
e.CancelEdit = true;
}
private void tree_AfterLabelEdit(object sender, NodeLabelEditEventArgs e)
{
string newLabel = e.Label == null ? tree.SelectedNode.Text : e.Label;
if (newLabel == tree.SelectedNode.Text)
return;
Base obj = tree.SelectedNode.Tag as Base;
bool duplicateName = false;
if (obj is DataSourceBase)
{
if (report.Dictionary.FindByAlias(newLabel) != null)
duplicateName = true;
else
{
(obj as DataSourceBase).Alias = newLabel;
}
}
else if (obj is Column)
{
// get column name, take parent columns into account
string columnName = newLabel;
TreeNode node = tree.SelectedNode;
while (true)
{
node = node.Parent;
if (node.Tag is DataSourceBase)
break;
columnName = node.Text + "." + columnName;
}
DataSourceBase data = obj.Parent as DataSourceBase;
if (data.Columns.FindByAlias(columnName) != null)
duplicateName = true;
else
(obj as Column).Alias = columnName;
}
else if (obj is Parameter)
{
TreeNode parentNode = tree.SelectedNode.Parent;
ParameterCollection parent = null;
if (parentNode.Tag is Parameter)
parent = (parentNode.Tag as Parameter).Parameters;
else
parent = report.Dictionary.Parameters;
if (parent.FindByName(newLabel) != null)
duplicateName = true;
else
obj.Name = newLabel;
}
else if (obj is Total)
{
if (report.Dictionary.FindByName(newLabel) != null)
duplicateName = true;
else
obj.Name = newLabel;
}
if (duplicateName)
{
e.CancelEdit = true;
FRMessageBox.Error(Res.Get("Designer,ToolWindow,Dictionary,DuplicateName"));
}
else
Change();
}
private void tree_ItemDrag(object sender, ItemDragEventArgs e)
{
draggedItems.Clear();
foreach (TreeNode n in tree.SelectedNodes)
{
string selectedItem = "";
TreeNode node = n;
if (node == null)
continue;
if (node.Tag is Column && !(node.Tag is DataSourceBase))
{
while (true)
{
if (node.Tag is DataSourceBase)
{
selectedItem = (node.Tag as DataSourceBase).FullName + "." + selectedItem;
break;
}
selectedItem = node.Text + (selectedItem == "" ? "" : ".") + selectedItem;
node = node.Parent;
}
}
else if (node.Tag is Parameter || node.Tag is Total)
{
while (node != null && node.Tag != null)
{
if (node.Tag is Parameter || node.Tag is Total)
selectedItem = node.Text + (selectedItem == "" ? "" : ".") + selectedItem;
node = node.Parent;
}
}
else if (node.Tag is MethodInfo)
{
MethodInfo info = node.Tag as MethodInfo;
ParameterInfo[] pars = info.GetParameters();
int parsLength = pars.Length;
if (parsLength > 0 && pars[0].Name == "thisReport")
parsLength--;
selectedItem = info.Name + "(" + (parsLength > 1 ? "".PadRight(parsLength - 1, ',') : "") + ")";
}
if (selectedItem != "")
draggedItems.Add(new DraggedItem(n.Tag, selectedItem));
}
if (draggedItems.Count > 0)
tree.DoDragDrop(draggedItems, DragDropEffects.Move);
else
tree.DoDragDrop(e.Item, DragDropEffects.None);
}
private void tree_DragOver(object sender, DragEventArgs e)
{
dragIndicator.Hide();
if (draggedItems.Count == 0)
return;
var pos = tree.PointToClient(new Point(e.X, e.Y));
TreeNode targetNode = tree.GetNodeAt(pos);
if (targetNode == null)
return;
object target = targetNode.Tag;
// the only thing that can be dragged around the DictionaryWindow is a report parameter
// allowed moves are:
// - target is ParameterCollection: add node to collection or set its z-order to 0 if node is in collection already
// - target is Parameter and dragged is not target and is not a root of target: reparent or change z-order (see notes below)
// additional check is required against SystemVariable(s) because they are subclasses of Parameter/ParameterCollection
if (target is SystemVariable || target is SystemVariables)
return;
int allow = 0;
foreach (DraggedItem draggedItem in draggedItems)
{
object dragged = draggedItem.obj;
if (dragged is Parameter dr && !(dragged is SystemVariable))
{
if (target is ParameterCollection ||
(target is Parameter tr && target != dragged && !tr.HasParent(dr)))
{
allow++;
}
}
}
if (allow != 0 && allow == draggedItems.Count)
{
e.Effect = e.AllowedEffect;
// check cursor position: less than 1/3 of target node width => change z-order, else change parent
int _20 = Designer.LogicalToDevice(20);
Rectangle dragRect = target is Parameter && pos.X < targetNode.Bounds.X + targetNode.Bounds.Width / 3 ?
new Rectangle(_20, targetNode.Bounds.Top, tree.Width - _20 * 2, 0) :
new Rectangle(targetNode.Bounds.Left, targetNode.Bounds.Bottom, targetNode.Bounds.Width, 0);
dragIndicator.BackColor = tree.ForeColor;
dragIndicator.SetBounds(tree.Left + dragRect.Left, tree.Top + dragRect.Top, dragRect.Width, Designer.LogicalToDevice(2));
dragIndicator.Show();
}
}
private void tree_DragDrop(object sender, DragEventArgs e)
{
dragIndicator.Hide();
if (draggedItems.Count == 0)
return;
var pos = tree.PointToClient(new Point(e.X, e.Y));
TreeNode targetNode = tree.GetNodeAt(pos);
if (targetNode == null)
return;
object target = targetNode.Tag;
if (target is SystemVariable || target is SystemVariables)
return;
string draggedName = "";
foreach (DraggedItem draggedItem in draggedItems)
{
Parameter dragged = draggedItem.obj as Parameter;
if (dragged == null || dragged is SystemVariable)
continue;
if (target is ParameterCollection collection)
{
if (collection.IndexOf(dragged) == -1)
{
FixParameterName(dragged, collection);
collection.Add(dragged);
}
}
else if (target is Parameter targetPar)
{
if (pos.X < targetNode.Bounds.X + targetNode.Bounds.Width / 3)
{
// insert dragged before target
dragged.ParentCollection.Remove(dragged);
var targetParentCollection = targetPar.ParentCollection;
FixParameterName(dragged, targetParentCollection);
targetParentCollection.Insert(targetParentCollection.IndexOf(targetPar), dragged);
}
else
{
if (targetPar.Parameters.IndexOf(dragged) == -1)
{
FixParameterName(dragged, targetPar.Parameters);
dragged.Parent = targetPar;
}
}
}
draggedName = dragged.FullName;
}
// update all designer plugins (this one too)
Designer.SetModified(null, "EditData");
NavigateTo(Res.Get("Designer,ToolWindow,Dictionary,Parameters") + "." + draggedName);
}
private void tree_DragLeave(object sender, EventArgs e)
{
dragIndicator.Hide();
}
private void FixParameterName(Parameter p, ParameterCollection coll)
{
p.Name = coll.CreateUniqueName(p.Name);
}
#endregion
#region Public Methods
///
public override void SelectionChanged()
{
base.SelectionChanged();
if (Designer.SelectedObjects.Count == 0 || Designer.SelectedObjects[0] is ComponentBase)
{
updating = true;
tree.SelectedNode = null;
updating = false;
UpdateControls();
}
}
///
public override void UpdateContent()
{
report = Designer.ActiveReport;
Throttle.Execute(() =>
{
UpdateTree();
// to save search results in DataTree when changing ReportTree
#if !WPF
SearchMatches();
#endif
});
}
///
public override void Localize()
{
base.Localize();
MyRes res = new MyRes("Designer,ToolWindow,Dictionary");
Text = res.Get("");
btnActions.Text = Res.Get("Buttons,Actions");
btnEdit.ToolTipText = res.Get("Edit");
btnDelete.ToolTipText = res.Get("Delete");
btnView.ToolTipText = res.Get("View");
miNew.Text = res.Get("New");
miOpen.Text = res.Get("Open");
miMerge.Text = res.Get("Merge");
miSave.Text = res.Get("Save");
miChooseData.Text = Res.Get("Designer,Menu,Data,Choose");
miNewDataSource.Text = miNewDataSource1.Text = res.Get("NewDataSource");
miSortDataSources.Text = miSortDataSources1.Text = res.Get("SortDataSources");
miNewRelation.Text = res.Get("NewRelation");
miNewParameter.Text = miNewParameter1.Text = res.Get("NewParameter");
miNewTotal.Text = miNewTotal1.Text = res.Get("NewTotal");
miNewCalculatedColumn.Text = miNewCalculatedColumn1.Text = res.Get("NewCalculatedColumn");
miRename.Text = res.Get("Rename");
miEdit.Text = res.Get("Edit");
miDelete.Text = res.Get("Delete");
miDeleteAlias.Text = res.Get("DeleteAlias");
miView.Text = res.Get("View");
miViewJson.Text = res.Get("ViewJson");
miSortDataFields.Text = res.Get("SortDataFields");
miCopyDataSource.Text = res.Get("CopyDataSource");
miUploadDataSource.Text = miUploadDataSource1.Text = res.Get("UploadDataSource");
UpdateTree();
}
///
public override void UpdateUIStyle()
{
base.UpdateUIStyle();
mnuContext.UpdateUIStyle();
splitter.BackColor = UIStyleUtils.GetControlColor(Designer.UIStyle);
}
///
public override void UpdateDpiDependencies()
{
base.UpdateDpiDependencies();
Image = Designer.GetImage(72);
tree.ImageList = mnuContext.ImageList = Designer.GetImages();
mnuContext.Font = btnActions.Font = Designer.LogicalToDevice(DrawUtils.DefaultFont);
btnActions.UpdateDpiDependencies(Designer);
}
///
public override void SaveState()
{
base.SaveState();
Storage.SetDip("DescriptionHeight", lblDescription.Height);
}
///
public override void RestoreState()
{
base.RestoreState();
lblDescription.Height = Storage.GetDip("DescriptionHeight", 50, 50, 200);
}
#endregion
///
/// Initializes a new instance of the class with default settings.
///
/// The report designer.
public DictionaryWindow(Designer designer)
: base(designer)
{
Name = "DictionaryWindow";
btnActions = new ToolbarDropDownButton("", -1, btnActions_DropDownOpening);
btnEdit = AddButton(68, miEdit_Click);
btnDelete = AddButton(51, miDelete_Click);
btnView = AddButton(54, miView_Click);
toolbar.Items.Insert(0, btnActions);
toolbar.Items.Insert(1, btnEdit);
toolbar.Items.Insert(2, btnDelete);
toolbar.Items.Insert(3, btnView);
miNew = AddMenuItem(0, miNew_Click);
miOpen = AddMenuItem(1, miOpen_Click);
miMerge = AddMenuItem(miMerge_Click);
miSave = AddMenuItem(2, miSave_Click);
miChooseData = AddMenuItem(Designer.cmdChooseData.Invoke);
miChooseData.BeginGroup = true;
miSortDataSources = AddMenuItem(Designer.cmdSortDataSources.Invoke);
miUploadDataSource = AddMenuItem(264, miUploadDataSource_Click);
miNewDataSource = AddMenuItem(137, Designer.cmdAddData.Invoke);
miNewDataSource.BeginGroup = true;
miNewRelation = AddMenuItem(139, miNewRelation_Click);
miNewCalculatedColumn = AddMenuItem(55, miNewCalculatedColumn_Click);
miNewParameter = AddMenuItem(56, miNewParameter_Click);
miNewTotal = AddMenuItem(65, miNewTotal_Click);
btnActions.AddDropDownItems(
miNew, miOpen, miMerge, miSave,
miChooseData, miSortDataSources,
#if !COMMUNITY
miUploadDataSource,
#endif
miNewDataSource, miNewRelation, miNewCalculatedColumn, miNewParameter, miNewTotal);
mnuContext = new ContextMenuBase(designer);
miSortDataSources1 = AddMenuItem(Designer.cmdSortDataSources.Invoke);
miUploadDataSource1 = AddMenuItem(206, miUploadDataSource_Click);
miNewDataSource1 = AddMenuItem(137, Designer.cmdAddData.Invoke);
miNewCalculatedColumn1 = AddMenuItem(55, miNewCalculatedColumn_Click);
miNewParameter1 = AddMenuItem(56, miNewParameter_Click);
miNewTotal1 = AddMenuItem(65, miNewTotal_Click);
miRename = AddMenuItem(miRename_Click);
//miRename.ShortcutKeys = Keys.F2;
miEdit = AddMenuItem(68, miEdit_Click);
miCopyDataSource = AddMenuItem(6, miCopyDataSource_Click);
miDelete = AddMenuItem(51, miDelete_Click);
miDeleteAlias = AddMenuItem(miDeleteAlias_Click);
miView = AddMenuItem(54, miView_Click);
miViewJson = AddMenuItem(54, miViewJson_Click);
miSortDataFields = AddMenuItem(miSortDataFields_Click);
mnuContext.Opening += mnuContext_Opening;
tree.AllowDrop = true;
tree.SelectionChanged += tree_SelectionChanged;
tree.RightMouseButtonClicked += tree_RightMouseButtonClicked;
tree.BeforeLabelEdit += tree_BeforeLabelEdit;
tree.AfterLabelEdit += tree_AfterLabelEdit;
tree.KeyDown += tree_KeyDown;
tree.DoubleClick += miEdit_Click;
tree.ItemDrag += tree_ItemDrag;
tree.DragOver += tree_DragOver;
tree.DragDrop += tree_DragDrop;
tree.DragLeave += tree_DragLeave;
dragIndicator = new Panel();
dragIndicator.Visible = false;
splitter = new Splitter();
splitter.Dock = DockStyle.Bottom;
splitter.Visible = false;
lblDescription = new DescriptionControl();
lblDescription.Dock = DockStyle.Bottom;
lblDescription.Height = 70;
lblDescription.Visible = false;
Controls.AddRange(new Control[] { dragIndicator, splitter, lblDescription });
Controls.SetChildIndex(dragIndicator, 0);
expandedNodes = new List();
Localize();
UpdateDpiDependencies();
}
///
/// Describes an item dragged from the "Data Dictionary" window.
///
public class DraggedItem
{
///
/// The dragged object.
///
public Object obj;
///
/// The text of dragged object.
///
public string text;
internal DraggedItem(Object obj, string text)
{
this.obj = obj;
this.text = text;
}
}
///
/// Collection of dragged items.
///
public class DraggedItemCollection : List
{
internal DraggedItemCollection() : base() { }
}
internal static class DragUtils
{
public static DraggedItemCollection GetAll(DragEventArgs e)
{
// holding dragged objects data in DragEventArgs does not work in Mono. Use simpler way
//DraggedItemCollection items = (DraggedItemCollection)e.Data.GetData(typeof(DraggedItemCollection));
DraggedItemCollection items = DictionaryWindow.draggedItems;
if (items == null || items.Count == 0)
return null;
return items;
}
public static DraggedItem GetOne(DragEventArgs e)
{
DraggedItemCollection items = DictionaryWindow.draggedItems;
if (items == null || items.Count == 0)
return null;
return items[items.Count - 1];
}
}
}
}