using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using CaeJob; using FileInOut.Output.Calculix; using CaeGlobals; using FastColoredTextBoxNS; using System.IO; using System.Text.RegularExpressions; using System.Collections.ObjectModel; using System.Reflection; using UserControls; namespace CPSO.Forms { public partial class FrmCalculixKeywordEditor : PrePoMaxChildForm { // dll routines [System.Runtime.InteropServices.DllImport("user32.dll")] public static extern bool LockWindowUpdate(IntPtr hWndLock); // Variables private List _keywords; private OrderedDictionary _userKeywords; private int _selectedKeywordFirstLine; private int _selectedKeywordNumOfLines; private bool _adding; // Styles private Style[] allStyles; private Style GreenStyle = new TextStyle(Brushes.Green, new SolidBrush(Color.FromArgb(230, 255, 230)), FontStyle.Regular); private Style BlueStyle = new TextStyle(Brushes.Blue, null, FontStyle.Regular); private Style GrayStyle = new TextStyle(Brushes.Gray, null, FontStyle.Regular); // Properties public List Keywords { get { return _keywords; } set { _keywords = value; } } public OrderedDictionary UserKeywords { get { return _userKeywords; } set { _userKeywords = value; } } // Constructors public FrmCalculixKeywordEditor() { InitializeComponent(); // allStyles = new Style[] { GreenStyle, BlueStyle, GrayStyle }; } // Event handlers private void cltvKeywordsTree_AfterSelect(object sender, TreeViewEventArgs e) { if (cltvKeywordsTree.SelectedNode != null) { bool userNode = false; // if (cltvKeywordsTree.SelectedNode.Tag is KeywordAtNode kn1 && kn1.Keyword is CalculixUserKeyword) userNode = true; // De-reference text changed event fctbKeyword.TextChanged -= fctbKeyword_TextChanged; // Clear keyword textbox fctbKeyword.Clear(); // Add keyword data to keyword textbox fctbKeyword.Tag = cltvKeywordsTree.SelectedNode.Tag; if (fctbKeyword.Tag != null && fctbKeyword.Tag is KeywordAtNode kn2) { fctbKeyword.Text = kn2.Data; fctbKeyword.ReadOnly = !userNode; // _selectedKeywordNumOfLines = kn2.NumOfLines; } else { _selectedKeywordFirstLine = 0; _selectedKeywordNumOfLines = 0; } // Find the first line of the selected keyword bool nodeFound = false; _selectedKeywordFirstLine = GetFirstLineOfSelectedNode(cltvKeywordsTree.Nodes[0], cltvKeywordsTree.SelectedNode, ref nodeFound); // Re-reference text changed event fctbKeyword.TextChanged += fctbKeyword_TextChanged; // UpdateKeywordTextBox(); } } // private void fctbKeyword_KeyDown(object sender, KeyEventArgs e) { //if (e.Control && e.KeyCode == Keys.V) //{ // ((RichTextBox)sender).Paste(DataFormats.GetFormat("Text")); // e.Handled = true; //} } private void fctbKeyword_TextChanged(object sender, TextChangedEventArgs e) { System.Diagnostics.Debug.WriteLine(DateTime.Now.Millisecond.ToString() + " ms"); tUpdate.Stop(); tUpdate.Start(); tUpdate.Interval = 500; } private void fctbInpFile_TextChanged(object sender, TextChangedEventArgs e) { // Set style e.ChangedRange.ClearStyle(allStyles); e.ChangedRange.SetStyle(GreenStyle, @"\*\*.*$", RegexOptions.Multiline); e.ChangedRange.SetStyle(BlueStyle, @"\*.*$", RegexOptions.Multiline); e.ChangedRange.SetStyle(GrayStyle, @"\.\.\..*$", RegexOptions.Multiline); } private void btnAddKeyword_Click(object sender, EventArgs e) { if (cltvKeywordsTree.SelectedNode != null) { _adding = true; LockWindowUpdate(cltvKeywordsTree.Handle); // CalculixUserKeyword keyword = new CalculixUserKeyword("User keyword"); TreeNode node = cltvKeywordsTree.SelectedNode.Nodes.Add("User keyword"); // cltvKeywordsTree.Focus(); // must be first AddUserKeywordToTreeNode(keyword, node); cltvKeywordsTree.SelectedNode.Expand(); cltvKeywordsTree.SelectedNode = node; // LockWindowUpdate(IntPtr.Zero); _adding = false; } } private void btnMoveUp_Click(object sender, EventArgs e) { if (cltvKeywordsTree.SelectedNode != null) { TreeNode node = cltvKeywordsTree.SelectedNode; //if (node.Tag is KeywordAtNode kn && kn.Keyword is CalculixUserKeyword) { TreeNodeCollection collection; TreeNode parent = cltvKeywordsTree.SelectedNode.Parent; if (parent != null) collection = parent.Nodes; else collection = cltvKeywordsTree.Nodes; // int index = collection.IndexOf(node); if (index > 0) { TreeNode nodeTop = collection[index - 1]; TreeNode nodeBottom = collection[index]; // At least one keyword must be a user keyword if (nodeTop.Tag is KeywordAtNode knt && knt.Keyword is CalculixUserKeyword || nodeBottom.Tag is KeywordAtNode knb && knb.Keyword is CalculixUserKeyword) { cltvKeywordsTree.SelectedNode = nodeTop; btnMoveDown_Click(null, null); cltvKeywordsTree.SelectedNode = node; } } } } } private void btnMoveDown_Click(object sender, EventArgs e) { if (cltvKeywordsTree.SelectedNode != null) { TreeNode node = cltvKeywordsTree.SelectedNode; // TreeNodeCollection collection; TreeNode parent = node.Parent; if (parent != null) collection = parent.Nodes; else collection = cltvKeywordsTree.Nodes; // int index = collection.IndexOf(node); if (index < collection.Count - 1) { TreeNode nodeTop = collection[index]; TreeNode nodeBottom = collection[index + 1]; // At least one keyword must be a user keyword if (nodeTop.Tag is KeywordAtNode knt && knt.Keyword is CalculixUserKeyword || nodeBottom.Tag is KeywordAtNode knb && knb.Keyword is CalculixUserKeyword) { // int numOfLinesTop = GetNumberOfLinesOfNode(nodeTop); string textTop = ReplaceText(_selectedKeywordFirstLine, numOfLinesTop, null); int numOfLinesBottom = GetNumberOfLinesOfNode(nodeBottom); string textBottom = ReplaceText(_selectedKeywordFirstLine, numOfLinesBottom, null); // ReplaceText(_selectedKeywordFirstLine, 0, textTop); ReplaceText(_selectedKeywordFirstLine, 0, textBottom); // LockWindowUpdate(cltvKeywordsTree.Handle); collection.RemoveAt(index); collection.Insert(index + 1, node); LockWindowUpdate(IntPtr.Zero); // cltvKeywordsTree.SelectedNode = node; } } } } private void btnDelete_Click(object sender, EventArgs e) { try { if (cltvKeywordsTree.SelectedNode != null) DeleteKeywordByTreeNode(cltvKeywordsTree.SelectedNode); } catch (Exception ex) { ExceptionTools.Show(this, ex); } } // private void cbHide_CheckedChanged(object sender, EventArgs e) { UpdateAllKeywords(); } // private void btnOK_Click(object sender, EventArgs e) { _userKeywords = new OrderedDictionary("User CalculiX keywords"); // FindUserKeywords(cltvKeywordsTree.Nodes[0], _userKeywords); // this.DialogResult = DialogResult.OK; } private void FindUserKeywords(TreeNode node, OrderedDictionary userKeywords) { if (node.Tag != null && node.Tag is KeywordAtNode kn && kn.Keyword is CalculixUserKeyword userKeyword) { List indices = new List(); GetNodeIndices(node, indices); userKeywords.Add(indices.ToArray(), userKeyword); } // foreach (TreeNode childNode in node.Nodes) { FindUserKeywords(childNode, userKeywords); } } private void GetNodeIndices(TreeNode node, List indices) { TreeNode parent = node.Parent; if (parent != null) { GetNodeIndices(parent, indices); // indices.Add(parent.Nodes.IndexOf(node)); } } // Methods public void PrepareForm() { cltvKeywordsTree.Nodes.Clear(); fctbKeyword.Clear(); fctbInpFile.Clear(); // TreeNode node = new TreeNode(); node.Text = "CalculiX inp file"; // Build the keyword tree int index; foreach (CalculixKeyword keyword in _keywords) { index = node.Nodes.Add(new TreeNode()); AddKeywordToTreeNode(keyword, node.Nodes[index]); } // Add user keywords if (_userKeywords != null) { foreach (var entry in _userKeywords) { AddUserKeywordToTreeByIndex(node, entry.Key, entry.Value.DeepClone()); } } // At the end add nodes to the tree cltvKeywordsTree.Nodes.Add(node); // Clear the keyword editor fctbKeyword.Clear(); // Output tree to the inp read-only textbox WriteTreeToTextBox(); // Expand first tree node node.Expand(); // _selectedKeywordFirstLine = -1; _selectedKeywordNumOfLines = -1; _adding = false; // if (node.Nodes.Count > 1) cltvKeywordsTree.SelectedNode = node.Nodes[0]; } private void UpdateAllKeywords() { UpdateKeywordDataInTree(); // WriteTreeToTextBox(); // cltvKeywordsTree_AfterSelect(null, null); } // Add keywords to tree private void AddKeywordToTreeNode(CalculixKeyword keyword, TreeNode node) { string nodeText; if (keyword is CalTitle ct) nodeText = ct.Title; else nodeText = keyword.GetKeywordString(); // nodeText = GetFirstLineFromMultiline(nodeText); // node.Text = nodeText; node.Name = node.Text; // KeywordAtNode keywordAtNode = new KeywordAtNode(); keywordAtNode.Keyword = keyword; keywordAtNode.Data = FileInOut.Output.CalculixFileWriter.GetShortKeywordData(keyword, cbHide.Checked); keywordAtNode.NumOfLines = keywordAtNode.Data.Split(new string[] { Environment.NewLine }, StringSplitOptions.None).Length; node.Tag = keywordAtNode; // int count = 0; foreach (var childKeyword in keyword.Keywords) { TreeNode childNode = new TreeNode(); node.Nodes.Add(childNode); AddKeywordToTreeNode(childKeyword, childNode); count++; } } private void AddUserKeywordToTreeByIndex(TreeNode node, int[] indices, CalculixKeyword keyword) { for (int i = 0; i < indices.Length - 1; i++) { node.Expand(); if (indices[i] < node.Nodes.Count) { node = node.Nodes[indices[i]]; } else return; } // TreeNode child = node.Nodes.Insert(indices[indices.Length - 1], ""); // User keyword should not be deactivated in the user editor to enable editing AddUserKeywordToTreeNode(keyword, child); // node.Expand(); } private void AddUserKeywordToTreeNode(CalculixKeyword keyword, TreeNode node) { node.Text = GetFirstLineFromMultiline(keyword.GetKeywordString()); // KeywordAtNode keywordAtNode = new KeywordAtNode(); keywordAtNode.Keyword = keyword; keywordAtNode.Data = FileInOut.Output.CalculixFileWriter.GetShortKeywordData(keyword, cbHide.Checked); keywordAtNode.NumOfLines = keywordAtNode.Data.Split(new string[] { Environment.NewLine }, StringSplitOptions.None).Length; node.Tag = keywordAtNode; Font font = new Font(cltvKeywordsTree.Font, FontStyle.Bold); node.NodeFont = font; //node.BackColor = Color.FromArgb(195, 195, 255); //node.BackColor = Color.FromArgb(230, 255, 230); //node.BackColor = Color.FromArgb(230, 255, 230); //node.ForeColor = Color.Green; //node.BackColor = Color.FromArgb(149, 91, 165); node.ForeColor = Color.Black; node.BackColor = Color.FromArgb(189, 160, 204); } private void UpdateKeywordDataInTree() { foreach (TreeNode node in cltvKeywordsTree.Nodes) { UpdateKeywordDataInTreeNode(node); } } private void UpdateKeywordDataInTreeNode(TreeNode node) { if (node.Tag != null && node.Tag is KeywordAtNode kn) { kn.Data = FileInOut.Output.CalculixFileWriter.GetShortKeywordData(kn.Keyword, cbHide.Checked); kn.NumOfLines = kn.Data.Split(new string[] { Environment.NewLine }, StringSplitOptions.None).Length; } // foreach (TreeNode childNode in node.Nodes) { UpdateKeywordDataInTreeNode(childNode); } } // Write keywords from tree to inp textbox private void WriteTreeToTextBox() { if (cltvKeywordsTree.Nodes.Count > 0) { StringWriter sw = new StringWriter(); WriteTreeNodeToStringWriter(sw, cltvKeywordsTree.Nodes[0]); // fctbInpFile.Text = sw.ToString(); } } private void WriteTreeNodeToStringWriter(StringWriter sw, TreeNode node) { if (node.Tag != null && node.Tag is KeywordAtNode kn) { sw.WriteLine(kn.Data); } // foreach (TreeNode childNode in node.Nodes) { WriteTreeNodeToStringWriter(sw, childNode); } } private int GetFirstLineOfSelectedNode(TreeNode node, TreeNode selectedNode, ref bool nodeFound) { int count = 0; // if (!nodeFound) { if (node == selectedNode) nodeFound = true; else { if (node.Tag != null && node.Tag is KeywordAtNode kn) count += kn.NumOfLines; // foreach (TreeNode childNode in node.Nodes) { count += GetFirstLineOfSelectedNode(childNode, selectedNode, ref nodeFound); if (nodeFound) break; } } } return count; } private int GetNumberOfLinesOfNode(TreeNode node) { int numOfLines = 0; if (node.Tag != null && node.Tag is KeywordAtNode kn) numOfLines += kn.NumOfLines; // foreach (TreeNode childNode in node.Nodes) numOfLines += GetNumberOfLinesOfNode(childNode); return numOfLines; } // Delete keywords private void DeleteKeywordByTreeNode(TreeNode node) { if (node.Tag is KeywordAtNode kn && kn.Keyword is CalculixUserKeyword) { int numOfLines = GetNumberOfLinesOfNode(node); ReplaceText(_selectedKeywordFirstLine, numOfLines, null); // TreeNode parent = node.Parent; if (parent != null) { int index = Math.Max(0, node.Index - 1); parent.Nodes.Remove(node); if (parent.Nodes.Count > index) cltvKeywordsTree.SelectedNode = parent.Nodes[index]; else cltvKeywordsTree.SelectedNode = parent; } else { cltvKeywordsTree.Nodes.Remove(node); if (cltvKeywordsTree.Nodes.Count > 0) cltvKeywordsTree.SelectedNode = cltvKeywordsTree.Nodes[0]; } // cltvKeywordsTree.Focus(); } } // Update keyword text box private void UpdateKeywordTextBox() { try { // Set style fctbKeyword.Range.ClearStyle(allStyles); fctbKeyword.Range.SetStyle(GreenStyle, @"\*\*.*$", RegexOptions.Multiline); fctbKeyword.Range.SetStyle(BlueStyle, @"\*.*$", RegexOptions.Multiline); fctbKeyword.Range.SetStyle(GrayStyle, @"\.\.\..*$", RegexOptions.Multiline); // De-reference text changed event fctbKeyword.TextChanged -= fctbKeyword_TextChanged; // rtbKeyword.Tag is set by clicking on the tree node if (!fctbKeyword.ReadOnly && fctbKeyword.Tag != null && cltvKeywordsTree.SelectedNode != null) { KeywordAtNode keywordAtNode = fctbKeyword.Tag as KeywordAtNode; if (keywordAtNode.Keyword is CalculixUserKeyword userKeyword && userKeyword != null) { userKeyword.Data = fctbKeyword.Lines.ToArray().ToRows(fctbKeyword.Lines.Count); keywordAtNode.Data = fctbKeyword.Text; keywordAtNode.NumOfLines = fctbKeyword.Lines.Count; // ReplaceText(_selectedKeywordFirstLine, _selectedKeywordNumOfLines, userKeyword.Data); _selectedKeywordNumOfLines = fctbKeyword.Lines.Count; // Change the name of the Selected tree node LockWindowUpdate(cltvKeywordsTree.Handle); if (fctbKeyword.Lines.Count > 0 && fctbKeyword.Lines[0].Length > 0) { if (cltvKeywordsTree.SelectedNode.Text != fctbKeyword.Lines[0]) cltvKeywordsTree.SelectedNode.Text = fctbKeyword.Lines[0]; } else cltvKeywordsTree.SelectedNode.Text = "User keyword"; LockWindowUpdate(IntPtr.Zero); } } // SelectKeywordLinesAndScrollToSelection(); // Re-reference text changed event fctbKeyword.TextChanged += fctbKeyword_TextChanged; } catch { } } // private string ReplaceText(int firstLine, int numOfLines, string newText) { StringBuilder sb = new StringBuilder(); // if (firstLine >= 0) { if (_adding) numOfLines = 0; // int lastLine = firstLine + numOfLines; fctbInpFile.Selection.Start = new Place(0, firstLine); fctbInpFile.Selection.End = new Place(0, lastLine); // for (int i = firstLine; i < firstLine + numOfLines; i++) { if (i < firstLine + numOfLines - 1) sb.AppendLine(fctbInpFile.Selection.tb[i].Text); else sb.Append(fctbInpFile.Selection.tb[i].Text); } // fctbInpFile.ClearSelected(); // string text = newText; if (text != null) text += Environment.NewLine; fctbInpFile.InsertText(text); } // return sb.ToString(); } private void SelectKeywordLinesAndScrollToSelection() { if (_selectedKeywordFirstLine == -1) return; fctbInpFile.Navigate(_selectedKeywordFirstLine); fctbInpFile.Selection = new Range(fctbInpFile, 0, _selectedKeywordFirstLine, 0, _selectedKeywordFirstLine + _selectedKeywordNumOfLines ); } // private string GetFirstLineFromMultiline(string multiLineData) { string[] tmp = multiLineData.Split(new string[] { "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries); if (tmp.Length > 0) return tmp[0]; else return "User keyword"; } private void tUpdate_Tick(object sender, EventArgs e) { tUpdate.Stop(); UpdateKeywordTextBox(); } } }