//****************************************************************** /// <summary> /// Pastes the features from the clipboard to the ListView. (The /// DisplayedNode and the ListView are both updated.) /// </summary> private void PasteFeatures() { Debug.Assert(DisplayedNode != null); //************************************************************** // Prevent modification if the feature collection is read-only. if (ReadOnly) { return; } //************************************************************** // 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; } //************************************************************** // Use a RuleReader to read the first SyntaxNode represented by // the string data (that is, the root node of the find pattern // in the first rule). SyntaxNode oNode = null; try { TextReader oTextReader = new StringReader(sString); RuleReader oRuleReader = new RuleReader(oTextReader); if (oRuleReader.Read()) { oNode = 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 a node was not read // (because the string data represented an empty collection of // rules). if (oNode == null) { return; } //************************************************************** // For each of the node's features, call SetFeature() to display // the feature in the ListView and to copy it to the // DisplayedNode.Features collection. foreach (SyntaxFeature oFeature in oNode.Features) { SetFeature(oFeature.Name,oFeature.Value); } //************************************************************** // In the ListView, select the features that were pasted. moListView.SelectedItems.Clear(); foreach (ListViewItem oItem in moListView.Items) { string sName = oItem.SubItems[moNameColumn.Index].Text; if (oNode.Features.Contains(sName)) { oItem.Selected = true; } } //************************************************************** // Make sure the first selected feature is scrolled into view // and has focus within the ListView. if (moListView.SelectedItems.Count > 0) { moListView.SelectedItems[0].Focused = true; moListView.SelectedItems[0].EnsureVisible(); } }
//****************************************************************** /// <summary> /// Loads and displays the indicated rule file (sFileName). The /// Modified property is set to false after the file is loaded. /// </summary> public void LoadRuleFile(string sFileName) { //************************************************************** // Validate the parameters. if ((sFileName == null) || (sFileName == "")) { string sMessage = "Invalid argument: " + "RuleListViewer.LoadRuleFile() requires " + "a file name that is not null or blank."; throw new Exception(sMessage); } //************************************************************** // Clear the linked FindPatternViewer and ReplacePatternViewer. UpdateFindAndReplacePatternViewers(null); //************************************************************** // Reset the TreeTransferData object. ResetTreeTransferData(); //************************************************************** // Clear the undo information. ClearUndoInformation(); //************************************************************** // Clear the list of items in the ListView. moListView.Items.Clear(); //************************************************************** // Create a RuleReader to read from the indicated rule file. StreamReader oStreamReader = new StreamReader(sFileName); RuleReader oRuleReader = new RuleReader(oStreamReader); //************************************************************** // For each rule loaded from the rule file, create a new rule // item and append it to the ListView. while (oRuleReader.Read()) { RuleListViewerItem oRuleItem = new RuleListViewerItem(); oRuleItem.Text = oRuleReader.RuleName; oRuleItem.FindPatternRoot = oRuleReader.FindPatternRoot; oRuleItem.ReplacePatternRoot = oRuleReader.ReplacePatternRoot; moListView.Items.Add(oRuleItem); } //************************************************************** // Close the RuleReader. oRuleReader.Close(); //************************************************************** // Select the first item in the ListView. Make sure it is // scrolled into view and has focus within the ListView. if (moListView.Items.Count > 0) { ListViewItem oItem = moListView.Items[0]; oItem.Selected = true; oItem.EnsureVisible(); oItem.Focused = true; } //************************************************************** // Set the Modified property to false. Modified = false; //************************************************************** // Raise the SelectionChanged event. OnSelectionChanged(new EventArgs()); //************************************************************** // Raise the ListChanged event. OnListChanged(new EventArgs()); }
//****************************************************************** // EXAMPLE UNDO INFORMATION FOR A PASTE OPERATION // // Before the paste operation, suppose the ListView displays the // following items: // // (index 0) Item-A // (index 1) Item-B // (index 2) Item-C (selected) // (index 3) Item-D // (index 4) Item-E // (index 5) Item-F (selected) // (index 6) Item-G // // Suppose the clipboard contains (Item-X,Item-Y,Item-Z). After the // paste operation, the ListView will display the following items: // // (index 0) Item-A // (index 1) Item-B // (index 2) Item-X (selected) // (index 3) Item-Y (selected) // (index 4) Item-Z (selected) // (index 5) Item-C // (index 6) Item-D // (index 7) Item-E // (index 8) Item-F // (index 9) Item-G // // And the undo information will contain: // // FirstIndexForUndo = 2 // ItemCountForUndo = 3 // ParseTreesForUndo = () // // This undo information indicates what is needed to reverse the // paste operation: replace the 3 items starting at index 2 with // the items in the ParseTreesForUndo collection (which in this case // contains no items). //****************************************************************** /// <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 ParseListViewer.Paste() is not allowed " + "if ParseListViewer.CanPaste() returns false."; throw new Exception(sMessage); } //************************************************************** // Prevent modification to a read-only list. if (ReadOnly) { return; } //************************************************************** // Clear the undo information. ClearUndoInformation(); //************************************************************** // 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; } //************************************************************** // Use a RuleReader to read the all the rules represented by the // string data. // // Each rule is interpreted as a parse tree: the .RuleName will // be the displayed text in the list, the .FindPatternRoot is // the parse tree, and the .ReplacePatternRoot is ignored. TransferRuleCollection oParseTrees = new TransferRuleCollection(); try { TextReader oTextReader = new StringReader(sString); RuleReader oRuleReader = new RuleReader(oTextReader); while (oRuleReader.Read()) { TransferRule oRule = new TransferRule(); oRule.RuleName = oRuleReader.RuleName; oRule.FindPatternRoot = oRuleReader.FindPatternRoot; oRule.ReplacePatternRoot = null; oParseTrees.Add(oRule); } 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 collection of // parses (from the string data) is empty. if (oParseTrees.Count == 0) { return; } //************************************************************** // Set the Modified property to true. Modified = true; //************************************************************** // Determine the first index where the parses will be pasted. int iFirstIndex = 0; ParseListViewerItem oFirstSelectedItem = FirstSelectedItem(); if (oFirstSelectedItem != null) { //********************************************************** // Insert before the first selected item in the list. iFirstIndex = oFirstSelectedItem.Index; } else { //********************************************************** // If no items are selected, append after the last item in // the list. iFirstIndex = moListView.Items.Count; } //************************************************************** // Paste the parses. (The pasted parses will be selected.) InsertParses(iFirstIndex,oParseTrees); Debug.Assert(FirstSelectedItem() != null); //************************************************************** // Set the undo information. FirstIndexForUndo = iFirstIndex; ItemCountForUndo = oParseTrees.Count; ParseTreesForUndo.Clear(); //************************************************************** // Raise the ListChanged event. OnListChanged(new EventArgs()); }
//****************************************************************** /// <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()); }