//****************************************************************** // EXAMPLE UNDO INFORMATION FOR A DELETE OPERATION // // Before the delete operation, suppose the ListView displays the // following items: // // (index 0) Item-A // (index 1) Item-B (selected) // (index 2) Item-C // (index 3) Item-D // (index 4) Item-E (selected) // (index 5) Item-F (selected) // (index 6) Item-G // (index 7) Item-H // // After the delete operation, the ListView will display the // following items: // // (index 0) Item-A // (index 1) Item-C (selected) // (index 2) Item-D // (index 3) Item-G // (index 4) Item-H // // And the undo information will contain: // // FirstIndexForUndo = 1 // ItemCountForUndo = 2 // ParseTreesForUndo = (Item-B,Item-C,Item-D,Item-E,Item-F) // // This undo information indicates what is needed to reverse the // delete operation: replace the 2 items starting at index 1 with // the items in the ParseTreesForUndo collection. //****************************************************************** /// <summary> /// Deletes the current selection. /// </summary> public void Delete() { //************************************************************** // Validate the current state. if (! CanDelete()) { string sMessage = "Invalid state: " + "A call to ParseListViewer.Delete() is not allowed " + "if ParseListViewer.CanDelete() returns false."; throw new Exception(sMessage); } //************************************************************** // Prevent modification to a read-only list. if (ReadOnly) { return; } //************************************************************** // Set the Modified property to true. Modified = true; //************************************************************** // Clear the undo information. ClearUndoInformation(); //************************************************************** // Determine the first and last selected items. ParseListViewerItem oFirstSelectedItem = FirstSelectedItem(); ParseListViewerItem oLastSelectedItem = LastSelectedItem(); //************************************************************** // Create the undo information: // // Set iFirstIndexForUndo to the first selected index. // // Copy the parses from the first selected item through (and // including) the last selected item, storing the copied parses // in the oParseTreesForUndo collection. // // Count the parses in the oParseTreesForUndo collection that // were not selected. Set iItemCountForUndo to this count. // (These non-selected parses will not be deleted from the // list.) int iFirstIndexForUndo = 0; int iItemCountForUndo = 0; TransferRuleCollection oParseTreesForUndo = new TransferRuleCollection(); if ((oFirstSelectedItem != null) && (oLastSelectedItem != null)) { //********************************************************** // Set iFirstIndexForUndo to the first selected index. iFirstIndexForUndo = oFirstSelectedItem.Index; //********************************************************** // Copy the parses from the first selected item through (and // including) the last selected item. for (int iIndex = oFirstSelectedItem.Index; iIndex <= oLastSelectedItem.Index; ++iIndex) { ListViewItem oItem = moListView.Items[iIndex]; //****************************************************** // Get the parse from the ListView item. Debug.Assert(oItem is ParseListViewerItem); ParseListViewerItem oParseItem = (ParseListViewerItem) oItem; //****************************************************** // Copy the parse information and add it to the // oParseTreesForUndo collection. (Use the TransferRule // object's .FindPatternRoot to store the parse tree.) TransferRule oRule = new TransferRule(); oRule.RuleName = oParseItem.Text; oRule.FindPatternRoot = oParseItem.ParseTreeRoot; oRule.ReplacePatternRoot = null; oParseTreesForUndo.Add(oRule); //****************************************************** // Count the non-selected parses (that were copied to // oParseTreesForUndo but will not be deleted). if (! oItem.Selected) { ++iItemCountForUndo; } } } //************************************************************** // Delete the selected items from the ListView in reverse order. // (This prevents multiple selection changes that would update // the linked tree viewer multiple times.) for (int iIndex = (moListView.Items.Count - 1); iIndex >= 0; --iIndex) { ListViewItem oItem = moListView.Items[iIndex]; if (oItem.Selected) { oItem.Remove(); } } Debug.Assert(FirstSelectedItem() == null); //************************************************************** // Clear the linked ParseTreeViewer. UpdateParseTreeViewer(null); //************************************************************** // Set the undo information. FirstIndexForUndo = iFirstIndexForUndo; ItemCountForUndo = iItemCountForUndo; ParseTreesForUndo.Clear(); foreach (TransferRule oRule in oParseTreesForUndo) { ParseTreesForUndo.Add(oRule); } //************************************************************** // Select the item at the iFirstSelectedIndex position. If there // is no longer an item at that position, select the last item // in the list. if (iFirstIndexForUndo < moListView.Items.Count) { moListView.Items[iFirstIndexForUndo].Selected = true; } else { if (moListView.Items.Count > 0) { int iIndex = moListView.Items.Count - 1; moListView.Items[iIndex].Selected = true; } } //************************************************************** // Make sure the new selected item (if any) is scrolled into // view and has focus within the ListView. oFirstSelectedItem = FirstSelectedItem(); if (oFirstSelectedItem != null) { oFirstSelectedItem.EnsureVisible(); oFirstSelectedItem.Focused = true; } //************************************************************** // 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> /// Inserts the given parses (oParseTrees) into the ListView, /// starting at the indicated index (iFirstIndex). The inserted /// parses are selected. /// </summary> private void InsertParses(int iFirstIndex, TransferRuleCollection oParseTrees) { Debug.Assert(iFirstIndex >= 0); Debug.Assert(oParseTrees != null); Debug.Assert(oParseTrees.Count > 0); //************************************************************** // Clear the selection. ClearSelection(); //************************************************************** // Insert the given parses starting at the indicated index. int iIndex = iFirstIndex; foreach (TransferRule oRule in oParseTrees) { //********************************************************** // Create the item to display in the ListView. (Get the // item's displayed text from the TransferRule object's // .RuleName property and the parse tree from its // .FindPatternRoot property.) ParseListViewerItem oParseItem = new ParseListViewerItem(); oParseItem.Text = oRule.RuleName; oParseItem.ParseTreeRoot = oRule.FindPatternRoot; //********************************************************** // Insert or append the item in the ListView. if (iIndex < moListView.Items.Count) { moListView.Items.Insert(iIndex,oParseItem); } else { moListView.Items.Add(oParseItem); } //********************************************************** // Select the item and make sure it is scrolled into view. oParseItem.Selected = true; oParseItem.EnsureVisible(); //********************************************************** // Increment the index. ++iIndex; } //************************************************************** // Make sure the first selected item is scrolled into view and // has focus within the ListView. ParseListViewerItem oFirstSelectedItem = FirstSelectedItem(); if (oFirstSelectedItem != null) { oFirstSelectedItem.EnsureVisible(); oFirstSelectedItem.Focused = true; } }
//****************************************************************** /// <summary> /// Undoes the last edit operation. /// </summary> public void Undo() { //************************************************************** // Validate the current state. if (! CanUndo()) { string sMessage = "Invalid state: " + "A call to ParseListViewer.Undo() is not allowed " + "if ParseListViewer.CanUndo() returns false."; throw new Exception(sMessage); } //************************************************************** // Prevent modification to a read-only tree. if (ReadOnly) { return; } //************************************************************** // Set the Modified property to true. Modified = true; //************************************************************** // Clear the selection. ClearSelection(); //************************************************************** // Clear the linked ParseTreeViewer. UpdateParseTreeViewer(null); //************************************************************** // Make a copy of the undo information. // // Note: Read the comments before the Paste() and Delete() // methods to see examples of what the undo information looks // like. int iFirstIndexForUndo = FirstIndexForUndo; int iItemCountForUndo = ItemCountForUndo; TransferRuleCollection oParseTreesForUndo = new TransferRuleCollection(); foreach (TransferRule oRule in ParseTreesForUndo) { oParseTreesForUndo.Add(oRule); } //************************************************************** // Clear the undo information. ClearUndoInformation(); //************************************************************** // Make a copy of the parses that will be replaced. (Starting at // index iFirstIndexForUndo, copy the number of parses specified // by iItemCountForUndo.) Debug.Assert(iFirstIndexForUndo >= 0); Debug.Assert(iItemCountForUndo >= 0); Debug.Assert((iFirstIndexForUndo + iItemCountForUndo) <= moListView.Items.Count); TransferRuleCollection oReplacedParses = new TransferRuleCollection(); for (int iIndex = iFirstIndexForUndo; iIndex < (iFirstIndexForUndo + iItemCountForUndo); ++iIndex) { if (iIndex < moListView.Items.Count) { ListViewItem oItem = moListView.Items[iIndex]; //****************************************************** // Get the parse from the ListView item. Debug.Assert(oItem is ParseListViewerItem); ParseListViewerItem oParseItem = (ParseListViewerItem) oItem; //****************************************************** // Copy the parse information and add it to the // oReplacedParses collection. (Use the TransferRule // object's .FindPatternRoot to store the parse tree.) TransferRule oRule = new TransferRule(); oRule.RuleName = oParseItem.Text; oRule.FindPatternRoot = oParseItem.ParseTreeRoot; oRule.ReplacePatternRoot = null; oReplacedParses.Add(oRule); } } //************************************************************** // Delete the parses that are being replaced. (Starting at index // iFirstIndexForUndo, delete the number of parses specified by // iItemCountForUndo.) if (iItemCountForUndo > 0) { DeleteParses(iFirstIndexForUndo,iItemCountForUndo); } //************************************************************** // Insert the replacement parses (from the undo information in // oParseTreesForUndo). The inserted parses will be selected. if (oParseTreesForUndo.Count > 0) { InsertParses(iFirstIndexForUndo,oParseTreesForUndo); } //************************************************************** // Unselect any parses that appear with the same information in // the oReplacedParses collection. (We do not want parses to be // selected if they were already in the list when the undo // command was issued.) foreach (ListViewItem oItem in moListView.Items) { //********************************************************** // Get the parse from the ListView item. Debug.Assert(oItem is ParseListViewerItem); ParseListViewerItem oParseItem = (ParseListViewerItem) oItem; //********************************************************** // Does the parse have the same information as a parse in // the oReplacedParses collection? If so, unselect it. if (oParseItem.Selected) { foreach (TransferRule oRule in oReplacedParses) { if ((oParseItem.Text == oRule.RuleName) && (oParseItem.ParseTreeRoot == oRule.FindPatternRoot)) { oParseItem.Selected = false; } } } } //************************************************************** // Select the item at the iFirstSelectedIndex position. If there // is no longer an item at that position, select the last item // in the list. if (iFirstIndexForUndo < moListView.Items.Count) { moListView.Items[iFirstIndexForUndo].Selected = true; } else { if (moListView.Items.Count > 0) { int iIndex = moListView.Items.Count - 1; moListView.Items[iIndex].Selected = true; } } //************************************************************** // Make sure the new selected item (if any) is scrolled into // view and has focus within the ListView. ParseListViewerItem oFirstSelectedItem = FirstSelectedItem(); if (oFirstSelectedItem != null) { oFirstSelectedItem.EnsureVisible(); oFirstSelectedItem.Focused = true; } //************************************************************** // Raise the SelectionChanged event. OnSelectionChanged(new EventArgs()); //************************************************************** // Raise the ListChanged event. OnListChanged(new EventArgs()); }
//****************************************************************** /// <summary> /// Inserts the given rules (oTransferRules) into the ListView, /// starting at the indicated index (iFirstIndex). The inserted /// rules are selected. /// </summary> private void InsertRules(int iFirstIndex, TransferRuleCollection oTransferRules) { Debug.Assert(iFirstIndex >= 0); Debug.Assert(oTransferRules != null); Debug.Assert(oTransferRules.Count > 0); //************************************************************** // Clear the selection. ClearSelection(); //************************************************************** // Insert the given rules starting at the indicated index. int iIndex = iFirstIndex; foreach (TransferRule oRule in oTransferRules) { //********************************************************** // Create the item to display in the ListView. RuleListViewerItem oRuleItem = new RuleListViewerItem(); oRuleItem.Text = oRule.RuleName; oRuleItem.FindPatternRoot = oRule.FindPatternRoot; oRuleItem.ReplacePatternRoot = oRule.ReplacePatternRoot; //********************************************************** // Insert or append the item in the ListView. if (iIndex < moListView.Items.Count) { moListView.Items.Insert(iIndex,oRuleItem); } else { moListView.Items.Add(oRuleItem); } //********************************************************** // Select the item and make sure it is scrolled into view. oRuleItem.Selected = true; oRuleItem.EnsureVisible(); //********************************************************** // Increment the index. ++iIndex; } //************************************************************** // Make sure the first selected item is scrolled into view and // has focus within the ListView. RuleListViewerItem oFirstSelectedItem = FirstSelectedItem(); if (oFirstSelectedItem != null) { oFirstSelectedItem.EnsureVisible(); oFirstSelectedItem.Focused = true; } }
//****************************************************************** /// <summary> /// Uses the displayed list of transfer rules to process the parse /// trees in the indicated input file (sParseFileName). The modified /// parse trees are written to the indicate output file /// (sOutputFileName). A modal dialog displays status information as /// the file is processed. The dialog is automatically closed when /// the processing is finished. DialogResult.OK is returned if the /// process completed successfully. DialogResult.Cancel is returned /// if the process was canceled or if an error occurred. /// </summary> public DialogResult ProcessParseFileAndClose(string sParseFileName, string sOutputFileName) { //************************************************************** // Validate the current state. if (moListView.Items.Count == 0) { string sMessage = "The parse file could not be processed " + "because the list of transfer rules is empty."; throw new Exception(sMessage); } //************************************************************** // Validate the parameters. if ((sParseFileName == null) || (sParseFileName == "")) { string sMessage = "Invalid argument: " + "RuleListViewer.ProcessParseFileAndClose() requires " + "a parse-file name that is not null or blank."; throw new Exception(sMessage); } if ((sOutputFileName == null) || (sOutputFileName == "")) { string sMessage = "Invalid argument: " + "RuleListViewer.ProcessParseFileAndClose() requires " + "an output-file name that is not null or blank."; throw new Exception(sMessage); } //************************************************************** // Copy the transfer rules from the displayed list. TransferRuleCollection oTransferRules = new TransferRuleCollection(); foreach (ListViewItem oItem in moListView.Items) { //********************************************************** // Get the rule from the ListView item. Debug.Assert(oItem is RuleListViewerItem); RuleListViewerItem oRuleItem = (RuleListViewerItem) oItem; //********************************************************** // Copy the rule information and add it to the // oTransferRules collection. TransferRule oRule = new TransferRule(); oRule.RuleName = oRuleItem.Text; oRule.FindPatternRoot = oRuleItem.FindPatternRoot; oRule.ReplacePatternRoot = oRuleItem.ReplacePatternRoot; oTransferRules.Add(oRule); } //************************************************************** // Perform the tree-transfer processing. DialogResult iResult = TransferForm.ProcessParseFileAndClose( oTransferRules,sParseFileName,sOutputFileName); //************************************************************** // Return the dialog result. return iResult; }
//****************************************************************** /// <summary> /// Uses the given transfer rules (oTransferRules) to process the /// parse trees in the indicated input file (sInputFileName). The /// modified parse trees are written to the indicate output file /// (sOutputFileName). A modal dialog displays status information as /// the file is processed. The dialog is automatically closed when /// the processing is finished. DialogResult.OK is returned if the /// process completed successfully. DialogResult.Cancel is returned /// if the process was canceled or if an error occurred. /// </summary> public static DialogResult ProcessParseFileAndClose( TransferRuleCollection oTransferRules,string sInputFileName, string sOutputFileName) { //************************************************************** // Validate the parameters. if (oTransferRules == null) { string sMessage = "Invalid argument: " + "TransferForm.ProcessParseFileAndClose() requires " + "a TransferRules collection that is not null."; throw new Exception(sMessage); } if (oTransferRules.Count == 0) { string sMessage = "Invalid argument: " + "TransferForm.ProcessParseFileAndClose() requires " + "a TransferRules collection that is not empty."; throw new Exception(sMessage); } if ((sInputFileName == null) || (sInputFileName == "")) { string sMessage = "Invalid argument: " + "TransferForm.ProcessParseFileAndClose() requires " + "an input-file name that is not null or blank."; throw new Exception(sMessage); } if ((sOutputFileName == null) || (sOutputFileName == "")) { string sMessage = "Invalid argument: " + "TransferForm.ProcessParseFileAndClose() requires " + "an output-file name that is not null or blank."; throw new Exception(sMessage); } //************************************************************** // Create an instance of the form. TransferForm oForm = new TransferForm(); //************************************************************** // Set the form's TransferRules, InputFileName, OutputFileName // and CloseWhenFinished property values. oForm.moTransferRules = oTransferRules; oForm.msInputFileName = sInputFileName; oForm.msOutputFileName = sOutputFileName; oForm.mbCloseWhenFinished = true; //************************************************************** // Show the form as a modal dialog. The form's Load event starts // a timer, and the timer's Tick event handler performs the // actual tree-transfer processing. DialogResult iResult = oForm.ShowDialog(); //************************************************************** // Return the dialog result when the form is closed. oForm.Close(); return iResult; }