//****************************************************************** /// <summary> /// Pastes the current contents of the clipboard. /// </summary> public void Paste() { //************************************************************** // Validate the current state. if (! CanPaste()) { string sMessage = "Invalid state: " + "A call to ParseTreeViewer.Paste() is not allowed " + "if ParseTreeViewer.CanPaste() returns false."; throw new Exception(sMessage); } //************************************************************** // Prevent modification to a read-only tree. if (ReadOnly) { return; } //************************************************************** // Use the current contents of the tree (before the paste // operation) to set the undo information. TreeTransferForUndo = RecreateTreeTransfer(); //************************************************************** // Get the string data on the clipboard, or return (without // reporting an error) if there is no string data on the // clipboard. IDataObject oDataObject = Clipboard.GetDataObject(); if (oDataObject == null) { return; } if (! oDataObject.GetDataPresent(typeof(string))) { return; } string sString = (string) oDataObject.GetData(typeof(string)); if (sString == null) { return; } //************************************************************** // Return (without reporting an error) if the string data does // not look at all like XML. if (sString.IndexOf("<") < 0) { return; } if (sString.IndexOf("/") < 0) { return; } if (sString.IndexOf(">") < 0) { return; } //************************************************************** // Get the branch to paste from the first tree represented by // the string data. SyntaxNode oSyntaxBranchToPaste = null; try { //********************************************************** // Use a RuleReader to read the first rule from the string. // Get the rule's FindPatternRoot as the branch to paste. TextReader oTextReader = new StringReader(sString); RuleReader oRuleReader = new RuleReader(oTextReader); if (oRuleReader.Read()) { oSyntaxBranchToPaste = oRuleReader.FindPatternRoot; } oRuleReader.Close(); } catch (Exception oException) { string sCaption = "Paste"; string sMessage = "Cannot paste because " + "the clipboard data is not compatible." + Environment.NewLine + Environment.NewLine + "(" + oException.Message + ")"; MessageBox.Show(sMessage,sCaption,MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } //************************************************************** // Return (without reporting an error) if the branch to paste // (from the string data) is null. if (oSyntaxBranchToPaste == null) { return; } //************************************************************** // If the displayed tree is a find pattern or a replace pattern, // the labels of the new nodes should all be unique. if ((DisplayFindPattern) || (DisplayReplacePattern)) { //********************************************************** // Collect all the node labels in the current tree. Then go // through the new branch and make sure all the nodes have // labels that are not already in use. SyntaxNode oSyntaxRoot = CloneTree(); if (oSyntaxRoot != null) { StringCollection oLabelsInUse = new StringCollection(); CollectLabelsInUse(oSyntaxRoot,oLabelsInUse); RenameLabelsInUse(oSyntaxBranchToPaste,oLabelsInUse); } } //************************************************************** // Call BeginUpdate() to disable redrawing the tree, but not if // redrawing was already disabled by the calling code. bool bCallEndUpdate = false; if (! IsUpdating) { BeginUpdate(); bCallEndUpdate = true; } //************************************************************** // If the root node is null or empty, paste a new tree. // Otherwise, paste a new child of the selected node. if (NodeIsNullOrEmpty(moTreeViewer.RootNode)) { //********************************************************** // Paste the branch as the root of the tree. Select the new // root node. moTreeViewer.RootNode = new TreeViewerNode(); PopulateBranch(moTreeViewer.RootNode,oSyntaxBranchToPaste); moTreeViewer.SelectedNode = moTreeViewer.RootNode; } else { //********************************************************** // Paste the branch as a child of the selected node. Select // the new child node that was pasted. if (moTreeViewer.SelectedNode != null) { //****************************************************** // The entire branch dominated by the selected node will // be repopulated. (This is because we want the pasted // branch to be displayed, even if ShowMorphology is // false and we are pasting a new morphology child of a // leaf node). // // First, clone the entire branch dominated by the // selected node. Delete the children of the selected // node in the tree. SyntaxNode oSyntaxParent = CloneBranch(moTreeViewer.SelectedNode); moTreeViewer.SelectedNode.ChildNodes.Clear(); //****************************************************** // Add the oSyntaxBranchToPaste as a child of the cloned // branch. Then use the cloned branch to repopulate the // branch in the tree dominated by the selected node. // // The oTreeTransfer.CurrentParseTreeNode is set to the // oSyntaxBranchToPaste, so this new child will be the // new selected node (even if it is a morphology node // and ShowMorphology is false). oSyntaxParent.ChildNodes.Add(oSyntaxBranchToPaste); TreeTransfer oTreeTransfer = new TreeTransfer(); oTreeTransfer.CurrentParseTreeNode = oSyntaxBranchToPaste; PopulateBranch(moTreeViewer.SelectedNode,oSyntaxParent, oTreeTransfer); } } //************************************************************** // Call EndUpdate() to redraw the tree, but not if redrawing was // already disabled by the calling code. if (bCallEndUpdate) { EndUpdate(); } //************************************************************** // Set the Modified property to true and raise the TreeChanged // event. Modified = true; OnTreeChanged(new EventArgs()); }
//****************************************************************** /// <summary> /// If the TreeTransferData object is null, it is set to a new /// TreeTransfer object. If the TreeTransferData object's /// .CurrentParseTreeNode is null, its .ParseTreeRoot is set to a /// copy of the parse tree in the linked ParseTreeViewer, and its /// .FindPatternRoot and .ReplacePatternRoot are set to the find /// and replace patterns indicated by the SelectedRule. /// </summary> private void InitializeTreeTransferData() { //************************************************************** // Set the TreeTransferData property to a new TreeTransfer // object if the TreeTransferData property is currently null. if (TreeTransferData == null) { TreeTransferData = new TreeTransfer(); } //************************************************************** // If TreeTransferData.CurrentParseTreeNode is null, set the // .ParseTreeRoot, .FindPatternRoot and .ReplacePatternRoot // properties of the TreeTransferData object. // // If TreeTransferData.CurrentParseTreeNode is not null, these // properties are not changed, because setting these properties // would clear the .CurrentParseTreeNode property (resetting the // current search position in the tree). if (TreeTransferData.CurrentParseTreeNode == null) { //********************************************************** // Set the TreeTransferData.ParseTreeRoot property to a copy // of the parse tree in the linked ParseTreeViewer. TreeTransferData.ParseTreeRoot = null; if (LinkedParseTreeViewer != null) { TreeTransferData.ParseTreeRoot = LinkedParseTreeViewer.CloneTree(); } //********************************************************** // Set the TreeTransferData.FindPatternRoot property to the // find-pattern of the SelectedRule. TreeTransferData.FindPatternRoot = null; if (SelectedRule != null) { TreeTransferData.FindPatternRoot = SelectedRule.FindPatternRoot; } if (TreeTransferData.FindPatternRoot == null) { TreeTransferData.FindPatternRoot = new SyntaxNode(); } //********************************************************** // Set the TreeTransferData.ReplacePatternRoot property to // the replace-pattern of the SelectedRule. TreeTransferData.ReplacePatternRoot = null; if (SelectedRule != null) { TreeTransferData.ReplacePatternRoot = SelectedRule.ReplacePatternRoot; } if (TreeTransferData.ReplacePatternRoot == null) { TreeTransferData.ReplacePatternRoot = new SyntaxNode(); } } }
//****************************************************************** /// <summary> /// Initializes a new instance of the MatchAlgorithm class, which /// will access the tree data through the given TreeTransfer object. /// </summary> public MatchAlgorithm(TreeTransfer oTreeTransfer) { Debug.Assert(oTreeTransfer != null); moTreeTransfer = oTreeTransfer; }
//****************************************************************** /// <summary> /// Opens the FeaturesForm to display the syntax features of the /// selected node. /// </summary> public void OpenFeatures() { //************************************************************** // Validate the current state. if (! CanOpenFeatures()) { string sMessage = "Invalid state: " + "A call to ParseTreeViewer.OpenFeatures() is not " + "allowed if ParseTreeViewer.CanOpenFeatures() " + "returns false."; throw new Exception(sMessage); } //************************************************************** // Clone the selected branch. // // We clone the entire branch dominated by the selected node so // we can repopulate this entire branch if the node's features // are changed. (We need to do this because the user could edit // the node-type feature, which determines if the node is a leaf // node whose morphology children might be hidden.) TreeViewerNode oTreeNode = moTreeViewer.SelectedNode; TreeTransfer oTreeTransfer = new TreeTransfer(); SyntaxNode oSyntaxNode = CloneBranch(oTreeNode,oTreeTransfer); //************************************************************** // Set the font for displaying features in the FeaturesForm to // the same font that this control uses to display parse trees. FeaturesForm.FeatureFont = Font; //************************************************************** // Open the FeaturesForm to display the features of the selected // node. (If ReadOnly is true, the user can view the features. // If ReadOnly is false, the user can also edit the features.) DialogResult iResult = DialogResult.None; if (ReadOnly) { iResult = FeaturesForm.OpenFeaturesReadOnly(oSyntaxNode); } else { iResult = FeaturesForm.OpenFeatures(oSyntaxNode); } //************************************************************** // Return without making any changes if the user canceled out of // the FeaturesForm. if (iResult != DialogResult.OK) { return; } //************************************************************** // Clear the undo information. TreeTransferForUndo = null; //************************************************************** // Determine if the FeaturesForm.FavoriteTreeFeatures list is // now different from the private FavoriteTreeFeatures copy of // the list. (If so, we will need to refresh the whole tree to // show the new set of features.) bool bTreeFeaturesChanged = false; if (FavoriteTreeFeatures.Count == FeaturesForm.FavoriteTreeFeatures.Count) { for (int iIndex = 0; iIndex < FavoriteTreeFeatures.Count; ++iIndex) { if (FavoriteTreeFeatures[iIndex] != FeaturesForm.FavoriteTreeFeatures[iIndex]) { bTreeFeaturesChanged = true; } } } else { bTreeFeaturesChanged = true; } //************************************************************** // Call BeginUpdate() to disable redrawing the tree, but not if // redrawing was already disabled by the calling code. bool bCallEndUpdate = false; if (! IsUpdating) { BeginUpdate(); bCallEndUpdate = true; } //************************************************************** // Update the selected node. (But not if ReadOnly is true.) if (! ReadOnly) { //********************************************************** // Repopulate the entire branch dominated by the selected // node. // // First, delete the children of the selected node in the // tree. Then repopulate the branch to display any changes // to the features of the selected node (and any changes to // whether its children are hidden). oTreeNode.ChildNodes.Clear(); PopulateBranch(oTreeNode,oSyntaxNode,oTreeTransfer); } //************************************************************** // If the FeaturesForm.FavoriteTreeFeatures list was changed, // refresh the whole tree to show the new set of features. if (bTreeFeaturesChanged) { oTreeTransfer = RecreateTreeTransfer(); PopulateRoot(oTreeTransfer); } //************************************************************** // Call EndUpdate() to redraw the tree, but not if redrawing was // already disabled by the calling code. if (bCallEndUpdate) { EndUpdate(); } //************************************************************** // Set the Modified property to true and raise the TreeChanged // event. (But not if ReadOnly is true.) if (! ReadOnly) { Modified = true; OnTreeChanged(new EventArgs()); } }
//****************************************************************** /// <summary> /// Uses the .ParseTreeRoot property of the given oSelectedParse /// object to populate the linked ParseTreeViewer. The SelectedParse /// property is set to the given oSelectedParse object. /// </summary> private void UpdateParseTreeViewer( ParseListViewerItem oSelectedParse) { //************************************************************** // Use the given oSelectedParse to initialize a TreeTransfer // object, which will be used to populate the parse-tree viewer. // // If oSelectedParse is null, a blank node will be used to // populate the parse-tree viewer. // // If oSelectedParse is not null, its .ParseTreeRoot tree will // be used to populate the parse-tree viewer. TreeTransfer oTreeTransfer = new TreeTransfer(); if (oSelectedParse == null) { oTreeTransfer.ParseTreeRoot = new SyntaxNode(); oTreeTransfer.FindPatternRoot = null; oTreeTransfer.ReplacePatternRoot = null; } else { oTreeTransfer.ParseTreeRoot = oSelectedParse.ParseTreeRoot; oTreeTransfer.FindPatternRoot = null; oTreeTransfer.ReplacePatternRoot = null; } //************************************************************** // Temporarily set the SelectedParse property to null, because // we do not want the LinkedParseTreeViewer TreeChanged event to // update the SelectedParse (and set the Modified property to // true) when we populate the parse-tree viewer. moSelectedParse = null; //************************************************************** // Populate the linked parse-tree viewer. if (LinkedParseTreeViewer != null) { LinkedParseTreeViewer.PopulateTree(oTreeTransfer); } //************************************************************** // Now set the SelectedParse property to the given // oSelectedParse object, because we want the TreeChanged events // to update the SelectedParse (and set the Modified property to // true) when the user edits the parse tree. moSelectedParse = oSelectedParse; }
//****************************************************************** /// <summary> /// Uses the given oTreeNode to display features of the indicated /// oSyntaxNode. Children are then recursively added to oTreeNode to /// represent the children of oSyntaxNode (unless it is a leaf node /// and morphology nodes are hidden). If the optional oTreeTransfer /// argument is given, its CurrentParseTreeNode indicates the node /// to select, and items in its MatchingNodes and ReplacedNodes /// collections indicate nodes to highlight. /// </summary> private void PopulateBranch(TreeViewerNode oTreeNode, SyntaxNode oSyntaxNode) { TreeTransfer oTreeTransfer = new TreeTransfer(); PopulateBranch(oTreeNode,oSyntaxNode,oTreeTransfer); }
//****************************************************************** /// <summary> /// Uses the TreeTransferData object to populate the linked /// ParseTreeViewer. /// </summary> private void UpdateParseTreeViewer() { Debug.Assert(TreeTransferData != null); //************************************************************** // The LinkedParseTreeViewer TreeChanged event handler resets // the TreeTransferData object. But we do not want this to // happen when we populate the parse-tree viewer, because this // would reset the current search position in the tree. // // So, to prevent this, we save the TreeTransferData object, and // then temporarily set the TreeTransferData property to null. TreeTransfer oTreeTransferData = TreeTransferData; TreeTransferData = null; //************************************************************** // Populate the linked parse-tree viewer. if (LinkedParseTreeViewer != null) { LinkedParseTreeViewer.PopulateTree(oTreeTransferData); } //************************************************************** // Now we set the TreeTransferData property back to the saved // oTreeTransferData object. TreeTransferData = oTreeTransferData; }
//****************************************************************** /// <summary> /// Creates a branch of SyntaxNode objects representing the nodes /// and features displayed by the given oTreeNode and its children /// (recursively). If the optional oTreeTransfer argument is given, /// its CurrentParseTreeNode is set to indicate the selected node /// (if any) in the branch, and items are added to its MatchingNodes /// and ReplacedNodes collections to indicate highlighted nodes in /// the branch. The root node of the created SyntaxNode branch is /// returned. /// </summary> private SyntaxNode CloneBranch(TreeViewerNode oTreeNode) { TreeTransfer oTreeTransfer = new TreeTransfer(); return CloneBranch(oTreeNode,oTreeTransfer); }
//****************************************************************** /// <summary> /// Creates a branch of SyntaxNode objects representing the nodes /// and features displayed by the given oTreeNode and its children /// (recursively). If the optional oTreeTransfer argument is given, /// its CurrentParseTreeNode is set to indicate the selected node /// (if any) in the branch, and items are added to its MatchingNodes /// and ReplacedNodes collections to indicate highlighted nodes in /// the branch. The root node of the created SyntaxNode branch is /// returned. /// </summary> private SyntaxNode CloneBranch(TreeViewerNode oTreeNode, TreeTransfer oTreeTransfer) { Debug.Assert(oTreeNode != null); Debug.Assert(oTreeTransfer != null); //************************************************************** // Clone the SyntaxNode branch associated with the given // oTreeNode. SyntaxNode oSyntaxNode = CloneNode(oTreeNode); //************************************************************** // The oTreeNode can have child nodes. Or the oSyntaxNode can // have child nodes (representing morphology nodes that were not // shown). But the oTreeNode and oSyntaxNode cannot both have // child nodes. if (oTreeNode.ChildNodes.Count > 0) { Debug.Assert(oSyntaxNode.ChildNodes.Count == 0); } if (oSyntaxNode.ChildNodes.Count > 0) { Debug.Assert(oTreeNode.ChildNodes.Count == 0); } //************************************************************** // Recursively clone each child branch of oTreeNode, and add // each cloned branch as a child of oSyntaxNode. foreach (TreeViewerNode oTreeChild in oTreeNode.ChildNodes) { SyntaxNode oSyntaxChild = CloneBranch(oTreeChild,oTreeTransfer); oSyntaxNode.ChildNodes.Add(oSyntaxChild); } //************************************************************** // If this node is the SelectedNode, set the // oTreeTransfer.CurrentParseTreeNode property to indicate this // node. if (oTreeNode == moTreeViewer.SelectedNode) { oTreeTransfer.CurrentParseTreeNode = oSyntaxNode; } //************************************************************** // If this node is highlighted as a matching node, add an item // indicating this node to the oTreeTransfer.MatchingNodes // collection. // // If this node is highlighted as a replaced node, add an item // indicating this node to the oTreeTransfer.ReplacedNodes // collection. if ((! DisplayFindPattern) && (! DisplayReplacePattern)) { if (oTreeNode.BackColor == FindPatternColor) { SyntaxNodePair oNodePair = new SyntaxNodePair(); oNodePair.ParseTreeNode = oSyntaxNode; oTreeTransfer.MatchingNodes.Push(oNodePair); } if (oTreeNode.BackColor == ReplacePatternColor) { SyntaxNodeTriple oNodeTriple = new SyntaxNodeTriple(); oNodeTriple.ParseTreeNode = oSyntaxNode; oTreeTransfer.ReplacedNodes.Push(oNodeTriple); } } //************************************************************** // Return the cloned SyntaxNode branch. return oSyntaxNode; }
//****************************************************************** /// <summary> /// Returns true if the specified tree branch (dominated by /// oSyntaxNode) contains a node to be selected or highlighted (as /// indicated by the CurrentParseTreeNode, MatchingNodes and /// ReplacedNodes properties of the given oTreeTransfer object). /// Returns false otherwise. /// </summary> private bool BranchContainsSelectionOrHighlight( SyntaxNode oSyntaxNode,TreeTransfer oTreeTransfer) { Debug.Assert(oSyntaxNode != null); Debug.Assert(oTreeTransfer != null); //************************************************************** // Use the oTreeTransfer.CurrentParseTreeNode property to // determine if this node is selected. if (oSyntaxNode == oTreeTransfer.CurrentParseTreeNode) { return true; } //************************************************************** // Use the oTreeTransfer.MatchingNodes and .ReplacedNodes // collections to determine if this node is highlighted. foreach (SyntaxNodePair oNodePair in oTreeTransfer.MatchingNodes) { if (oSyntaxNode == oNodePair.ParseTreeNode) { return true; } } foreach (SyntaxNodeTriple oNodeTriple in oTreeTransfer.ReplacedNodes) { if (oSyntaxNode == oNodeTriple.ParseTreeNode) { return true; } } //************************************************************** // Search the child branches recursively. foreach (SyntaxNode oSyntaxChild in oSyntaxNode.ChildNodes) { if (BranchContainsSelectionOrHighlight( oSyntaxChild,oTreeTransfer)) { return true; } } return false; }
//****************************************************************** /// <summary> /// Undoes the last edit operation. /// </summary> public void Undo() { //************************************************************** // Validate the current state. if (! CanUndo()) { string sMessage = "Invalid state: " + "A call to ParseTreeViewer.Undo() is not allowed " + "if ParseTreeViewer.CanUndo() returns false."; throw new Exception(sMessage); } //************************************************************** // Prevent modification to a read-only tree. if (ReadOnly) { return; } //************************************************************** // Get the undo information and then clear the // TreeTransferForUndo property. TreeTransfer oTreeTransfer = TreeTransferForUndo; TreeTransferForUndo = null; //************************************************************** // Populate the tree using the undo information. PopulateRoot(oTreeTransfer); //************************************************************** // Set the Modified property to true and raise the TreeChanged // event. Modified = true; OnTreeChanged(new EventArgs()); }
//****************************************************************** /// <summary> /// Displays the parse tree specified by the ParseTreeRoot property /// of the given TreeTransfer object. The TreeTransfer object also /// specifies the node to select (CurrentParseTreeNode property) and /// the nodes to highlight (in the MatchingNodes and ReplacedNodes /// collections). /// </summary> public void PopulateTree(TreeTransfer oTreeTransfer) { //************************************************************** // Validate the parameters. if (oTreeTransfer == null) { string sMessage = "Invalid argument: " + "ParseTreeViewer.PopulateTree() requires " + "a TreeTransfer object that is not null."; throw new Exception(sMessage); } //************************************************************** // Clear the undo information. TreeTransferForUndo = null; //************************************************************** // Populate the tree. PopulateRoot(oTreeTransfer); //************************************************************** // Set the Modified property to false and raise the TreeChanged // event. Modified = false; OnTreeChanged(new EventArgs()); }
//****************************************************************** /// <summary> /// Sets the TreeTransferData object to null and then calls the /// InitializeTreeTransferData() method to reinitialize the /// TreeTransferData object. /// </summary> private void ResetTreeTransferData() { TreeTransferData = null; InitializeTreeTransferData(); }
//****************************************************************** /// <summary> /// Uses the given oTreeNode to display features of the indicated /// oSyntaxNode. Children are then recursively added to oTreeNode to /// represent the children of oSyntaxNode (unless it is a leaf node /// and morphology nodes are hidden). If the optional oTreeTransfer /// argument is given, its CurrentParseTreeNode indicates the node /// to select, and items in its MatchingNodes and ReplacedNodes /// collections indicate nodes to highlight. /// </summary> private void PopulateBranch(TreeViewerNode oTreeNode, SyntaxNode oSyntaxNode,TreeTransfer oTreeTransfer) { Debug.Assert(oTreeNode != null); Debug.Assert(oSyntaxNode != null); Debug.Assert(oTreeTransfer != null); //************************************************************** // The given oTreeNode should not already have children. Debug.Assert(oTreeNode.ChildNodes.Count == 0); //************************************************************** // Set the node's context menu. oTreeNode.ContextMenu = moMenu; //************************************************************** // Use the oTreeTransfer.CurrentParseTreeNode property to // determine if the node is selected. if (oSyntaxNode == oTreeTransfer.CurrentParseTreeNode) { moTreeViewer.SelectedNode = oTreeNode; } //************************************************************** // Use the oTreeTransfer.MatchingNodes and .ReplacedNodes // collections to determine the node's background color. Color oForeColor = SystemColors.WindowText; Color oBackColor = SystemColors.Window; foreach (SyntaxNodePair oNodePair in oTreeTransfer.MatchingNodes) { if (oSyntaxNode == oNodePair.ParseTreeNode) { oBackColor = FindPatternColor; } } foreach (SyntaxNodeTriple oNodeTriple in oTreeTransfer.ReplacedNodes) { if (oSyntaxNode == oNodeTriple.ParseTreeNode) { oBackColor = ReplacePatternColor; } } if (DisplayFindPattern) { oBackColor = FindPatternColor; } if (DisplayReplacePattern) { oBackColor = ReplacePatternColor; } oTreeNode.ForeColor = oForeColor; oTreeNode.BackColor = oBackColor; //************************************************************** // Determine if the node's children should be shown. // // A node's children are usually shown, but if the node is a // leaf node and ShowMorphology is false, the leaf node's // children (representing morphology) are not shown (unless the // leaf node's children are selected or highlighted). bool bShowChildNodes = true; if (oSyntaxNode.IsSyntaxLeaf) { if (! ShowMorphology) { bShowChildNodes = false; //****************************************************** // Even if ShowMorphology is false, a leaf node's // children are shown if any of the child branches // contains a selected or highlighted node. foreach (SyntaxNode oSyntaxChild in oSyntaxNode.ChildNodes) { if (BranchContainsSelectionOrHighlight( oSyntaxChild,oTreeTransfer)) { bShowChildNodes = true; } } } } //************************************************************** // Display the node (showing or hiding its children). if (bShowChildNodes) { //********************************************************** // Display the node and its children. // // Clone the oSyntaxNode (without including child nodes) and // call PopulateNode(). PopulateNode(oTreeNode,oSyntaxNode.CloneNode()); //********************************************************** // For each child node, add a new TreeViewerNode to the tree // and make a recursive call to PopulateBranch(). foreach (SyntaxNode oSyntaxChild in oSyntaxNode.ChildNodes) { TreeViewerNode oTreeChild = new TreeViewerNode(); oTreeNode.ChildNodes.Add(oTreeChild); PopulateBranch(oTreeChild,oSyntaxChild,oTreeTransfer); } } else { //********************************************************** // Display the node, but hide its children. // // Clone the entire oSyntaxNode branch (so the cloned branch // includes child nodes that represent morphology) and call // PopulateNode(). PopulateNode(oTreeNode,oSyntaxNode.CloneBranch()); } }
//****************************************************************** /// <summary> /// Uses the .FindPatternRoot and .ReplacePatternRoot properties of /// the given oSelectedRule object to populate the linked /// FindPatternViewer and ReplacePatternViewer. The SelectedRule /// property is set to the given oSelectedRule object. /// </summary> private void UpdateFindAndReplacePatternViewers( RuleListViewerItem oSelectedRule) { //************************************************************** // Use the given oSelectedRule to initialize a TreeTransfer // object, which will be used to populate the find-pattern and // replace-pattern viewers. // // If oSelectedRule is null, blank nodes will be used to // populate the find-pattern and replace-pattern viewers. // // If oSelectedRule is not null, its .FindPatternRoot tree and // .ReplacePatternRoot tree will be used to populate the // find-pattern and replace-pattern viewers. TreeTransfer oTreeTransfer = new TreeTransfer(); if (oSelectedRule == null) { oTreeTransfer.ParseTreeRoot = null; oTreeTransfer.FindPatternRoot = new SyntaxNode(); oTreeTransfer.ReplacePatternRoot = new SyntaxNode(); } else { oTreeTransfer.ParseTreeRoot = null; oTreeTransfer.FindPatternRoot = oSelectedRule.FindPatternRoot; oTreeTransfer.ReplacePatternRoot = oSelectedRule.ReplacePatternRoot; } //************************************************************** // Temporarily set the SelectedRule property to null, because we // do not want the LinkedFindPatternViewer TreeChanged event and // the LinkedReplacePatternViewer TreeChanged event to update // the SelectedRule (and set the Modified property to true) when // we populate the find-pattern and replace-pattern trees. moSelectedRule = null; //************************************************************** // Populate the linked find-pattern viewer. if (LinkedFindPatternViewer != null) { LinkedFindPatternViewer.PopulateTree(oTreeTransfer); } //************************************************************** // Populate the linked replace-pattern viewer. if (LinkedReplacePatternViewer != null) { LinkedReplacePatternViewer.PopulateTree(oTreeTransfer); } //************************************************************** // Now set the SelectedRule property to the given oSelectedRule // object, because we want the TreeChanged events to update the // SelectedRule (and set the Modified property to true) when the // user edits the find-pattern and replace-pattern trees. moSelectedRule = oSelectedRule; }
//****************************************************************** /// <summary> /// Displays the parse tree specified by the ParseTreeRoot property /// (or the FindPatternRoot or the DisplayPatternRoot) of the given /// TreeTransfer object. The TreeTransfer object also specifies the /// node to select (CurrentParseTreeNode property) and the nodes to /// highlight (in the MatchingNodes and ReplacedNodes collections). /// This method does not change the Modified property, raise the /// TreeChanged event or clear the undo information. /// </summary> private void PopulateRoot(TreeTransfer oTreeTransfer) { Debug.Assert(oTreeTransfer != null); //************************************************************** // Make a private copy of the FeaturesForm.FavoriteTreeFeatures // collection. This private copy will be used until the // PopulateRoot() method is called again, so this tree will // display a consistent set of features when parts of the tree // are edited (even if the FeaturesForm collection changes). FavoriteTreeFeatures.Clear(); foreach (string sName in FeaturesForm.FavoriteTreeFeatures) { FavoriteTreeFeatures.Add(sName); } //************************************************************** // Call BeginUpdate() to disable redrawing the tree, but not if // redrawing was already disabled by the calling code. bool bCallEndUpdate = false; if (! IsUpdating) { BeginUpdate(); bCallEndUpdate = true; } //************************************************************** // Get the root node that specifies the tree to display. // // Display the find-pattern tree if DisplayFindPattern is true. // Display the replace-pattern tree if DisplayReplacePattern is // true. Display the parse tree otherwise. SyntaxNode oSyntaxRoot = oTreeTransfer.ParseTreeRoot; if (DisplayFindPattern) { oSyntaxRoot = oTreeTransfer.FindPatternRoot; } if (DisplayReplacePattern) { oSyntaxRoot = oTreeTransfer.ReplacePatternRoot; } //************************************************************** // If the specified root node is null, display a blank node. if (oSyntaxRoot == null) { oSyntaxRoot = new SyntaxNode(); } //************************************************************** // Create the root TreeViewerNode and then call PopulateBranch() // to display the tree. TreeViewerNode oTreeRoot = new TreeViewerNode(); moTreeViewer.RootNode = oTreeRoot; PopulateBranch(oTreeRoot,oSyntaxRoot,oTreeTransfer); //************************************************************** // If no node is selected, select the root node. if (moTreeViewer.SelectedNode == null) { moTreeViewer.SelectedNode = moTreeViewer.RootNode; } //************************************************************** // Call EndUpdate() to redraw the tree, but not if redrawing was // already disabled by the calling code. if (bCallEndUpdate) { EndUpdate(); } }
//****************************************************************** /// <summary> /// Displays the find-pattern tree specified by the FindPatternRoot /// property of the given TreeTransfer object. /// </summary> public void PopulateTree(TreeTransfer oTreeTransfer) { //************************************************************** // The viewer must be set up to display find-pattern trees. Debug.Assert(moParseTreeViewer.DisplayFindPattern); Debug.Assert(moParseTreeViewer.ShowFeatures); Debug.Assert(moParseTreeViewer.ShowMorphology); //************************************************************** // Display the find-pattern tree. moParseTreeViewer.PopulateTree(oTreeTransfer); }
//****************************************************************** /// <summary> /// Returns a new TreeTransfer object that can be used to repopulate /// the tree. This TreeTransfer object points to a cloned copy of /// the current state of the tree. It also specifies the node to /// select (CurrentParseTreeNode property) and the nodes to /// highlight (in the MatchingNodes and ReplacedNodes collections). /// </summary> private TreeTransfer RecreateTreeTransfer() { //************************************************************** // Create a new TreeTransfer object. TreeTransfer oTreeTransfer = new TreeTransfer(); //************************************************************** // Set the TreeTransfer properties to represent the current // state of the tree. if (moTreeViewer.RootNode != null) { //********************************************************** // Clone the whole tree. SyntaxNode oSyntaxRoot = CloneBranch(moTreeViewer.RootNode,oTreeTransfer); //********************************************************** // Copy the CurrentParseTreeNode property and the // MatchingNodes and ReplacedNodes collections (since these // may be cleared when the ParseTreeRoot, FindPatternRoot // and ReplacePatternRoot properties of the TreeTransfer // object are set). SyntaxNode oCurrentParseTreeNode = oTreeTransfer.CurrentParseTreeNode; SyntaxNodePairStack oMatchingNodes = new SyntaxNodePairStack(); foreach (SyntaxNodePair oNodePair in oTreeTransfer.MatchingNodes) { oMatchingNodes.Push(oNodePair); } SyntaxNodeTripleStack oReplacedNodes = new SyntaxNodeTripleStack(); foreach (SyntaxNodeTriple oNodeTriple in oTreeTransfer.ReplacedNodes) { oReplacedNodes.Push(oNodeTriple); } //********************************************************** // If the parse tree is displayed, set the ParseTreeRoot // property to the root of the cloned tree. // // If the find-pattern tree is displayed, set the // FindPatternRoot property to the root of the cloned tree. // // If the replace-pattern tree is displayed, set the // ReplacePatternRoot property to the root of the cloned // tree. oTreeTransfer.ParseTreeRoot = oSyntaxRoot; oTreeTransfer.FindPatternRoot = null; oTreeTransfer.ReplacePatternRoot = null; if (DisplayFindPattern) { oTreeTransfer.ParseTreeRoot = null; oTreeTransfer.FindPatternRoot = oSyntaxRoot; } if (DisplayReplacePattern) { oTreeTransfer.ParseTreeRoot = null; oTreeTransfer.ReplacePatternRoot = oSyntaxRoot; } //********************************************************** // Set the CurrentParseTreeNode property and the items in // the MatchingNodes and ReplacedNodes collections, using // the values that were copied earlier. oTreeTransfer.CurrentParseTreeNode = oCurrentParseTreeNode; oTreeTransfer.MatchingNodes.Clear(); foreach (SyntaxNodePair oNodePair in oMatchingNodes) { oTreeTransfer.MatchingNodes.Push(oNodePair); } oTreeTransfer.ReplacedNodes.Clear(); foreach (SyntaxNodeTriple oNodeTriple in oReplacedNodes) { oTreeTransfer.ReplacedNodes.Push(oNodeTriple); } } //************************************************************** // Return the TreeTransfer object. return oTreeTransfer; }
//****************************************************************** /// <summary> /// Initializes a new instance of the ReplaceAlgorithm class, which /// will access the tree data through the given TreeTransfer object. /// </summary> public ReplaceAlgorithm(TreeTransfer oTreeTransfer) { Debug.Assert(oTreeTransfer != null); moTreeTransfer = oTreeTransfer; }
//****************************************************************** /// <summary> /// Deletes the current selection. /// </summary> public void Delete() { //************************************************************** // Validate the current state. if (! CanDelete()) { string sMessage = "Invalid state: " + "A call to ParseTreeViewer.Delete() is not allowed " + "if ParseTreeViewer.CanDelete() returns false."; throw new Exception(sMessage); } //************************************************************** // Prevent modification to a read-only tree. if (ReadOnly) { return; } //************************************************************** // Use the current contents of the tree (before the delete // operation) to set the undo information. TreeTransferForUndo = RecreateTreeTransfer(); //************************************************************** // Call BeginUpdate() to disable redrawing the tree, but not if // redrawing was already disabled by the calling code. bool bCallEndUpdate = false; if (! IsUpdating) { BeginUpdate(); bCallEndUpdate = true; } //************************************************************** // Delete the branch dominated by the selected node. if (moTreeViewer.SelectedNode != null) { if (moTreeViewer.SelectedNode == moTreeViewer.RootNode) { //****************************************************** // The selected node is the root node. // // Replace the root node with an empty node. Select the // new root node. moTreeViewer.RootNode = new TreeViewerNode(); SyntaxNode oSyntaxNode = new SyntaxNode(); PopulateBranch(moTreeViewer.RootNode,oSyntaxNode); moTreeViewer.SelectedNode = moTreeViewer.RootNode; } else { //****************************************************** // The selected node is not the root node. // // Remove the selected node. Select the parent of the // removed node. TreeViewerNode oTreeParent = moTreeViewer.SelectedNode.ParentNode; if (oTreeParent != null) { oTreeParent.ChildNodes .Remove(moTreeViewer.SelectedNode); moTreeViewer.SelectedNode = oTreeParent; } } } //************************************************************** // Call EndUpdate() to redraw the tree, but not if redrawing was // already disabled by the calling code. if (bCallEndUpdate) { EndUpdate(); } //************************************************************** // Set the Modified property to true and raise the TreeChanged // event. Modified = true; OnTreeChanged(new EventArgs()); }
//****************************************************************** /// <summary> /// The timer is fired once after the form is loaded, and this event /// handler performs the tree-transfer processing. It uses the /// collection of transfer rules to process the parse trees in the /// input file, and it writes the modified parse trees to the output /// file. /// </summary> private void moTimer_Tick(object oSender,EventArgs oArgs) { ParseReader oParseReader = null; ParseWriter oParseWriter = null; try { //********************************************************** // Stop the timer (so it only fires once after the form is // loaded). moTimer.Stop(); //********************************************************** // Initialize the information displayed on the form. Text = "Processing Parse File..."; moInputFileTextBox.Text = InputFileName; moOutputFileTextBox.Text = OutputFileName; moRuleCountTextBox.Text = TransferRules.Count.ToString(); moParseCountTextBox.Text = "0"; moInputFileTextBox.Select( moInputFileTextBox.Text.Length,0); moOutputFileTextBox.Select( moOutputFileTextBox.Text.Length,0); moRuleCountTextBox.Select( moRuleCountTextBox.Text.Length,0); moParseCountTextBox.Select( moParseCountTextBox.Text.Length,0); moParseCountTextBox.Focus(); moOKButton.Enabled = false; moCancelButton.Enabled = true; //********************************************************** // Make sure the form is visible. Show(); Application.DoEvents(); //********************************************************** // Open the input and output files. StreamReader oStreamReader = new StreamReader(InputFileName); oParseReader = new ParseReader(oStreamReader); StreamWriter oStreamWriter = new StreamWriter(OutputFileName); oParseWriter = new ParseWriter(oStreamWriter); //********************************************************** // Read and process each parse tree from the input file. int iCount = 0; ProcessingWasCanceled = false; while ((oParseReader.Read()) && (! ProcessingWasCanceled)) { //****************************************************** // Create a TreeTransfer object and set its // ParseTreeRoot to the parse tree that was read from // the input file. TreeTransfer oTransfer = new TreeTransfer(); oTransfer.ParseTreeRoot = oParseReader.ParseTreeRoot; //****************************************************** // Apply each rule in the TransferRules collection. foreach (TransferRule oRule in TransferRules) { oTransfer.FindPatternRoot = oRule.FindPatternRoot; oTransfer.ReplacePatternRoot = oRule.ReplacePatternRoot; //************************************************** // Apply the rule to each matching branch. oTransfer.CurrentParseTreeNode = null; while (oTransfer.FindNextMatchingBranch()) { oTransfer.ReplaceCurrentMatchingBranch(); } } //****************************************************** // Write the modified parse tree to the output file. oParseWriter.ParseTreeRoot = oTransfer.ParseTreeRoot; oParseWriter.Write(); //****************************************************** // Update the information displayed on the form. ++iCount; moParseCountTextBox.Text = iCount.ToString(); moParseCountTextBox.Select( moParseCountTextBox.Text.Length,0); //****************************************************** // Call DoEvents() so the form can update the display // and check if the user clicked the Cancel button. Application.DoEvents(); } //********************************************************** // Close the input and output files. oParseReader.Close(); oParseReader = null; oParseWriter.Close(); oParseWriter = null; //********************************************************** // Update the final information displayed on the form. if (ProcessingWasCanceled) { Text = "Processing Parse File... Canceled"; } else { Text = "Processing Parse File... Finished"; } moOKButton.Enabled = true; moCancelButton.Enabled = false; moOKButton.Focus(); //********************************************************** // If the Cancel button was clicked, set DialogResult to // DialogResult.Cancel, which will close the form. // // If the Cancel button was not clicked, but the // CloseWhenFinished property is true, set DialogResult to // DialogResult.OK, which will close the form. if (ProcessingWasCanceled) { DialogResult = DialogResult.Cancel; } else { if (CloseWhenFinished) { DialogResult = DialogResult.OK; } } } catch (Exception oException) { ShowException(oException); ProcessingWasCanceled = true; } try { //********************************************************** // Make sure the output file is closed (even if an exception // was thrown). if (oParseWriter != null) { oParseWriter.Close(); oParseWriter = null; } } catch (Exception oException) { ShowException(oException); ProcessingWasCanceled = true; } try { //********************************************************** // Make sure the OK button is enabled (even if an exception // was thrown). moOKButton.Enabled = true; moCancelButton.Enabled = false; moOKButton.Focus(); } catch (Exception oException) { ShowException(oException); ProcessingWasCanceled = true; } try { //********************************************************** // If the Cancel button was clicked (or an exception was // thrown), make sure DialogResult is set to // DialogResult.Cancel, which will close the form. if (ProcessingWasCanceled) { DialogResult = DialogResult.Cancel; } } catch (Exception oException) { ShowException(oException); } }