protected override void Do( BlockCommandContext context, Block block) { // Pull out some common elements we'll need. ProjectBlockCollection blocks = block.Blocks; int blockIndex = blocks.IndexOf(block) + 1; // Because of how block keys work, the ID is unique very time so we have // to update our inverse operation. addedBlocks.Clear(); // Go through and create each block at a time, adding it to the inverse // command as we create them. for (int count = 0; count < Count; count++) { // Create and insert a new block into the system. var newBlock = new Block(blocks); blocks.Insert(blockIndex, newBlock); // Keep track of the block so we can remove them later. addedBlocks.Add(newBlock); // Update the position. if (UpdateTextPosition.HasFlag(DoTypes.Do)) { context.Position = new BlockPosition(newBlock.BlockKey, 0); } } }
/// <summary> /// Configures the environment to load the plugin manager and verify we /// have access to the ImmediateCorrectionPlugin. /// </summary> private void SetupPlugin( out ProjectBlockCollection blocks, out BlockCommandSupervisor commands, out WordCounterProjectPlugin projectPlugin) { // Start getting us a simple plugin manager. var plugin = new WordCounterPlugin(); var pluginManager = new PluginManager(plugin); PluginManager.Instance = pluginManager; // Create a project and pull out the useful properties we'll use to // make changes. var project = new Project(); blocks = project.Blocks; commands = project.Commands; // Load in the immediate correction editor. if (!project.Plugins.Add("Word Counter")) { // We couldn't load it for some reason. throw new ApplicationException("Cannot load word counter plugin."); } // Pull out the controller for the correction and cast it (since we know // what type it is). ProjectPluginController pluginController = project.Plugins.Controllers[0]; projectPlugin = (WordCounterProjectPlugin)pluginController.ProjectPlugin; // Set up logging for the controller. WordCounterProjectPlugin.Logger = Console.WriteLine; }
public void TestUndoRedoCommand() { // Arrange var project = new Project(); var context = new BlockCommandContext(project); ProjectBlockCollection blocks = project.Blocks; Block block = blocks[0]; using (block.AcquireBlockLock(RequestLock.Write)) { block.SetText("Testing 123"); } BlockKey blockKey = block.BlockKey; var command = new InsertAfterBlockCommand(blockKey, 1); project.Commands.Do(command, context); project.Commands.Undo(context); // Act project.Commands.Redo(context); // Assert Assert.AreEqual(2, blocks.Count); Assert.AreEqual( new BlockPosition(blocks[1], 0), project.Commands.LastPosition); int index = 0; Assert.AreEqual("Testing 123", blocks[index].Text); index++; Assert.AreEqual("", blocks[index].Text); }
public override void Undo(BlockCommandContext context) { // If we have a block key, we use that first. ProjectBlockCollection blocks = context.Blocks; if (UseBlockKey) { Block block; using ( blocks.AcquireBlockLock( RequestLock.Write, RequestLock.Write, BlockKey, out block)) { Undo(context, block); } } else { Block block; using ( blocks.AcquireBlockLock( RequestLock.Write, RequestLock.Write, (int)Line, out block)) { Undo(context, block); } } }
public static void GetBeginAndEndCharacterIndices( this SingleLineTextRange range, ProjectBlockCollection blocks, out int blockIndex, out int sourceBegin, out int sourceEnd, out string text) { using (blocks.AcquireLock(RequestLock.Read)) { // Start by getting the block based on the index. Block block; blockIndex = range.LinePosition.GetLineIndex(blocks.Count); using ( blocks.AcquireBlockLock( RequestLock.Read, RequestLock.Read, blockIndex, out block)) { // Get the text and calculate the character indicies. text = block.Text; range.GetBeginAndEndCharacterIndices(text, out sourceBegin, out sourceEnd); } } }
public void TestUndoRedoCommand() { // Arrange var project = new Project(); var context = new BlockCommandContext(project); ProjectBlockCollection blocks = project.Blocks; Block block = blocks[0]; int blockVersion = block.Version; BlockKey blockKey = block.BlockKey; var command = new SetTextCommand(blockKey, "Testing 123"); project.Commands.Do(command, context); project.Commands.Undo(context); // Act project.Commands.Redo(context); // Assert Assert.AreEqual(1, blocks.Count); Assert.AreEqual( new BlockPosition(blocks[0], "Testing 123".Length), project.Commands.LastPosition); const int index = 0; Assert.AreEqual("Testing 123", blocks[index].Text); Assert.AreEqual(blockVersion + 3, blocks[index].Version); }
/// <summary> /// Writes out the project file to a given directory. /// </summary> /// <param name="directory">The directory to save the file.</param> public void Save(DirectoryInfo directory) { // Set up the project macros we'll be expanding. ProjectMacros macros = SetupMacros(directory); // Validate the state. string projectFilename = macros.ExpandMacros("{ProjectFilename}"); if (string.IsNullOrWhiteSpace(projectFilename)) { throw new InvalidOperationException( "Project filename is not defined in Settings property."); } // We need a write lock on the blocks to avoid changes. This also prevents // any background tasks from modifying the blocks during the save process. ProjectBlockCollection blocks = Project.Blocks; using (blocks.AcquireLock(RequestLock.Write)) { // Create a new project writer and write out the results. var projectWriter = new FilesystemPersistenceProjectWriter( Project, Settings, macros); var projectFile = new FileInfo(projectFilename); projectWriter.Write(projectFile); } }
public void TestUndoRedoCommand() { // Arrange var project = new Project(); var context = new BlockCommandContext(project); ProjectBlockCollection blocks = project.Blocks; Block block = blocks[0]; using (block.AcquireBlockLock(RequestLock.Write)) { block.SetText("abcd"); } int blockVersion = block.Version; BlockKey blockKey = block.BlockKey; var command = new ReplaceTextCommand( new BlockPosition(blockKey, 2), 1, "YES"); project.Commands.Do(command, context); project.Commands.Undo(context); // Act project.Commands.Redo(context); // Assert Assert.AreEqual(1, blocks.Count); Assert.AreEqual( new BlockPosition(blocks[0], 5), project.Commands.LastPosition); const int index = 0; Assert.AreEqual("abYESd", blocks[index].Text); Assert.AreEqual(blockVersion + 6, blocks[index].Version); }
/// <summary> /// Inserts the lines. /// </summary> /// <param name="project">The project.</param> /// <param name="lineCount">The line count.</param> private void InsertLines( Project project, int lineCount) { // Pull out some useful variables. ProjectBlockCollection blocks = project.Blocks; // Modify the first line, which is always there. using (blocks[0].AcquireBlockLock(RequestLock.Write)) { blocks[0].SetText("Line 1"); } // Add in the additional lines after the first one. for (int i = 1; i < lineCount; i++) { var block = new Block(blocks); using (block.AcquireBlockLock(RequestLock.Write)) { block.SetText("Line " + (i + 1)); } blocks.Add(block); } }
/// <summary> /// Creates a project with a set number of lines and gives them a state that /// can easily be tested for. /// </summary> /// <param name="context"></param> /// <param name="blocks">The block collection in the project.</param> /// <param name="blockTypes">The block types supervisor for the project.</param> /// <param name="commands">The commands supervisor for the project.</param> /// <param name="lineCount">The number of blocks to insert into the projects.</param> protected void SetupMultilineTest( out BlockCommandContext context, out ProjectBlockCollection blocks, out BlockTypeSupervisor blockTypes, out BlockCommandSupervisor commands, int lineCount = 4) { // Everything is based on the project. var project = new Project(); context = new BlockCommandContext(project); blocks = project.Blocks; commands = project.Commands; blockTypes = project.BlockTypes; // Insert the bulk of the lines. InsertLines(project, lineCount); // Go through and set up the block types for these elements. project.Blocks[0].SetBlockType(blockTypes.Chapter); for (int index = 1; index < project.Blocks.Count; index++) { project.Blocks[index].SetBlockType(blockTypes.Scene); } }
/// <summary> /// Configures the environment to load the plugin manager and verify we /// have access to the ImmediateCorrectionPlugin. /// </summary> private void SetupCorrectionPlugin( out BlockCommandContext context, out ProjectBlockCollection blocks, out BlockCommandSupervisor commands, out ImmediateCorrectionProjectPlugin projectPlugin) { // Start getting us a simple plugin manager. var plugin = new ImmediateCorrectionPlugin(); var pluginManager = new PluginManager(plugin); PluginManager.Instance = pluginManager; // Create a project and pull out the useful properties we'll use to // make changes. var project = new Project(); context = new BlockCommandContext(project); blocks = project.Blocks; commands = project.Commands; // Load in the immediate correction editor. if (!project.Plugins.Add("Immediate Correction")) { // We couldn't load it for some reason. throw new ApplicationException("Cannot load immediate correction plugin"); } // Pull out the controller for the correction and cast it (since we know // what type it is). ProjectPluginController pluginController = project.Plugins.Controllers[0]; projectPlugin = (ImmediateCorrectionProjectPlugin)pluginController.ProjectPlugin; }
public void Register(ProjectBlockCollection ownerCollection) { //ownerCollection.ItemsAdded += OnItemsAdded; //ownerCollection.ItemsRemoved += OnItemsRemoved; //ownerCollection.ItemRemovedAt += OnItemRemovedAt; //ownerCollection.ItemInserted += OnItemInserted; //ownerCollection.CollectionCleared += OnCollectionCleared; //ownerCollection.CollectionChanged += OnCollectionChanged; }
/// <summary> /// Writes the content file, to either the project Writer or the Structure /// file depending on the persistence settings. /// </summary> /// <param name="projectWriter">The project Writer.</param> public void Write(XmlWriter projectWriter) { // Figure out which Writer we'll be using. bool createdWriter; XmlWriter writer = GetXmlWriter( projectWriter, Macros, Settings.ContentDataFilename, out createdWriter); // Start by creating the initial element. writer.WriteStartElement("content-data", ProjectNamespace); writer.WriteElementString("version", "1"); // Write out the project properties. writer.WriteStartElement("project", ProjectNamespace); WriteProperties(writer, Project); writer.WriteEndElement(); // Go through the blocks in the list. ProjectBlockCollection blocks = Project.Blocks; for (int blockIndex = 0; blockIndex < blocks.Count; blockIndex++) { // Write out this block. Block block = blocks[blockIndex]; writer.WriteStartElement("block-data", ProjectNamespace); // Write out the text of the block so we can identify it later. It // normally will be in order, but this is a second verification // that won't change. writer.WriteStartElement("block-key", ProjectNamespace); writer.WriteAttributeString( "block-index", blockIndex.ToString(CultureInfo.InvariantCulture)); writer.WriteAttributeString( "text-hash", block.Text.GetHashCode().ToString("X8")); writer.WriteEndElement(); // For this pass, we write out the data generates by the plugins // and internal state. WriteProperties(writer, block); WriteAnalysisState(writer, block); WriteTextSpans(writer, block); // Finish up the block. writer.WriteEndElement(); } // Finish up the blocks element. writer.WriteEndElement(); // If we created the Writer, close it. if (createdWriter) { writer.Dispose(); } }
public static void GetBeginAndEndCharacterIndices( this SingleLineTextRange range, ProjectBlockCollection blocks, out int blockIndex, out int sourceBegin, out int sourceEnd) { string text; GetBeginAndEndCharacterIndices( range, blocks, out blockIndex, out sourceBegin, out sourceEnd, out text); }
public void TestInitialState() { // Act var project = new Project(); // Assert ProjectBlockCollection blocks = project.Blocks; Assert.AreEqual(1, blocks.Count); Block block = blocks[0]; Assert.AreEqual(string.Empty, block.Text); }
protected void SetupComplexMultilineTest( out ProjectBlockCollection blocks, out BlockTypeSupervisor blockTypes, out BlockCommandSupervisor commands, int lineCount = 10) { // Everything is based on the project. var project = new Project(); blocks = project.Blocks; commands = project.Commands; blockTypes = project.BlockTypes; // Set up the structure and insert the lines. SetupComplexMultilineTest(project, lineCount); }
/// <summary> /// Initializes a new instance of the <see cref="Project"/> class. /// </summary> public Project( ProjectProcessingState initialProcessingState = ProjectProcessingState.Interactive) { // Set up the initial states. ProcessingState = initialProcessingState; // We need the settings set up first since it may contribute // to the loading of other components of the project. Settings = new ProjectSettings(); Properties = new PropertiesDictionary(); BlockTypes = new BlockTypeSupervisor(this); Blocks = new ProjectBlockCollection(this); Commands = new BlockCommandSupervisor(this); Plugins = new PluginSupervisor(this); Macros = new ProjectMacros(); }
/// <summary> /// Configures the environment to load the plugin manager and verify we /// have access to our plugin and projectPlugin. /// </summary> private void SetupPlugin( out BlockCommandContext context, out ProjectBlockCollection blocks, out BlockCommandSupervisor commands, out PluginSupervisor plugins, out SpellEngineSpellingProjectPlugin projectPlugin) { // Start getting us a simple plugin manager. var spelling = new SpellingFrameworkPlugin(); var nhunspell = new HunspellSpellingPlugin(); var pluginManager = new PluginManager(spelling, nhunspell); PluginManager.Instance = pluginManager; // Create a project and pull out the useful properties we'll use to // make changes. var project = new Project(); context = new BlockCommandContext(project); blocks = project.Blocks; commands = project.Commands; plugins = project.Plugins; // Load in the immediate correction editor. if (!plugins.Add("Spelling Framework")) { // We couldn't load it for some reason. throw new ApplicationException("Cannot load 'Spelling' plugin."); } if (!plugins.Add("NHunspell")) { // We couldn't load it for some reason. throw new ApplicationException("Cannot load 'NHunspell' plugin."); } // Pull out the projectPlugin for the correction and cast it (since we know // what type it is). ProjectPluginController pluginController = plugins.Controllers[1]; projectPlugin = (SpellEngineSpellingProjectPlugin)pluginController.ProjectPlugin; }
protected void SetupComplexMultilineTest( Project project, int lineCount) { // Insert the bulk of the lines. InsertLines(project, lineCount); // Change the block types for the project. This basically builds up a // structure of one chapter with any number of scenes that have one // epigraph, one epigraph attribution, and two paragraphs. BlockTypeSupervisor blockTypes = project.BlockTypes; ProjectBlockCollection blocks = project.Blocks; blocks[0].SetBlockType(blockTypes.Chapter); for (int blockIndex = 1; blockIndex < blocks.Count; blockIndex++) { Block block = blocks[blockIndex]; if ((blockIndex - 1) % 5 == 0) { block.SetBlockType(blockTypes.Scene); } else if ((blockIndex - 2) % 5 == 0) { block.SetBlockType(blockTypes.Epigraph); } else if ((blockIndex - 3) % 5 == 0) { block.SetBlockType(blockTypes.EpigraphAttribution); } else { block.SetBlockType(blockTypes.Paragraph); } } // Let everything finish running. project.Plugins.WaitForBlockAnalzyers(); }
public void Undo(BlockCommandContext context) { // Since we're making chanegs to the list, we need a write lock. ProjectBlockCollection blocks = context.Blocks; using (blocks.AcquireLock(RequestLock.Write)) { // Go through all the blocks in the project. foreach (Block block in blocks) { if (Changes.ContainsKey(block.BlockKey)) { // Revert the type of this block. BlockType blockType = previousBlockTypes[block.BlockKey]; block.SetBlockType(blockType); } } } }
/// <summary> /// Writes the content file, to either the project Writer or the Structure /// file depending on the persistence settings. /// </summary> /// <param name="projectWriter">The project Writer.</param> public void Write(XmlWriter projectWriter) { // Figure out which Writer we'll be using. bool createdWriter; XmlWriter writer = GetXmlWriter( projectWriter, Macros, Settings.ContentFilename, out createdWriter); // Start by creating the initial element. writer.WriteStartElement("content", ProjectNamespace); writer.WriteElementString("version", "1"); // Go through the blocks in the project. ProjectBlockCollection blocks = Project.Blocks; foreach (Block block in blocks) { // Write the beginning of the block. writer.WriteStartElement("block", ProjectNamespace); // For this pass, we only include block elements that are // user-entered. We'll do a second pass to include the processed // data including TextSpans and parsing status later. writer.WriteElementString("type", ProjectNamespace, block.BlockType.Name); writer.WriteElementString("text", ProjectNamespace, block.Text); writer.WriteElementString( "text-hash", ProjectNamespace, block.Text.GetHashCode().ToString("X8")); // Finish up the block. writer.WriteEndElement(); } // Finish up the blocks element. writer.WriteEndElement(); // If we created the Writer, close it. if (createdWriter) { writer.Dispose(); } }
/// <summary> /// Configures the environment to load the plugin manager and verify we /// have access to our plugin and projectPlugin. /// </summary> private void SetupPlugin( out ProjectBlockCollection blocks, out BlockCommandSupervisor commands, out PluginSupervisor plugins, out FilesystemPersistenceProjectPlugin projectPlugin) { // Start getting us a simple plugin manager. var persistencePlugin = new PersistenceFrameworkPlugin(); var filesystemPlugin = new FilesystemPersistencePlugin(); var pluginManager = new PluginManager(persistencePlugin, filesystemPlugin); PluginManager.Instance = pluginManager; PersistenceManager.Instance = new PersistenceManager(persistencePlugin); // Create a project and pull out the useful properties we'll use to // make changes. var project = new Project(); blocks = project.Blocks; commands = project.Commands; plugins = project.Plugins; // Load in the plugins we'll be using in these tests. plugins.Add("Persistence Framework"); plugins.Add("Filesystem Persistence"); plugins.Add("Spelling Framework"); plugins.Add("NHunspell"); plugins.Add("Local Words"); plugins.Add("Immediate Correction"); // Pull out the projectPlugin for the correction and cast it (since we know // what type it is). ProjectPluginController pluginController = plugins.Controllers[1]; projectPlugin = (FilesystemPersistenceProjectPlugin)pluginController.ProjectPlugin; }
public void Run() { // Figure out which analyzers we need to actually run on the block. var neededAnalyzers = new List <IBlockAnalyzerProjectPlugin>(); foreach (IBlockAnalyzerProjectPlugin blockAnalyzer in BlockAnalyzers) { if (!Analysis.Contains(blockAnalyzer)) { neededAnalyzers.Add(blockAnalyzer); } } // Loop through all the analyzers in the list and perform each one in turn. ProjectBlockCollection blocks = Block.Project.Blocks; foreach (IBlockAnalyzerProjectPlugin blockAnalyzer in neededAnalyzers) { // Check to see if the block had gone stale. using (blocks.AcquireBlockLock(RequestLock.Read, Block)) { if (Block.IsStale(BlockVersion)) { // The block is stale, so we just dump out since there will be // another task to reanalyze this block. return; } } // Perform the analysis on the given block. blockAnalyzer.AnalyzeBlock(Block, BlockVersion); // Once we're done analyzing the block, we need to add this // analyzer to the list so we don't attempt to run it again. Block.AddAnalysis(blockAnalyzer); } }
public void Do(BlockCommandContext context) { // Since we're making chanegs to the list, we need a write lock. ProjectBlockCollection blocks = context.Blocks; using (blocks.AcquireLock(RequestLock.Write)) { // Clear out the undo list since we'll be rebuilding it. previousBlockTypes.Clear(); // Go through all the blocks in the project. foreach (Block block in blocks) { if (Changes.ContainsKey(block.BlockKey)) { BlockType blockType = Changes[block.BlockKey]; BlockType existingType = block.BlockType; previousBlockTypes[block.BlockKey] = existingType; block.SetBlockType(blockType); } } } }
/// <summary> /// Configures the environment to load the plugin manager and verify we /// have access to our plugin and projectPlugin. /// </summary> private void SetupPlugin( out ProjectBlockCollection blocks, out BlockCommandSupervisor commands, out PluginSupervisor plugins, out FilesystemPersistenceProjectPlugin projectPlugin) { // Start getting us a simple plugin manager. var persistencePlugin = new PersistenceFrameworkPlugin(); var filesystemPlugin = new FilesystemPersistencePlugin(); var spellingPlugin = new SpellingFrameworkPlugin(); var nhunspellPlugin = new HunspellSpellingPlugin(); var localWordsPlugin = new LocalWordsPlugin(); var immediateCorrectionPlugin = new ImmediateCorrectionPlugin(); var immediateBlockTypesPlugin = new ImmediateBlockTypesPlugin(); var blockStructurePlugin = new BlockStructurePlugin(); var pluginManager = new PluginManager( persistencePlugin, filesystemPlugin, spellingPlugin, nhunspellPlugin, localWordsPlugin, immediateCorrectionPlugin, immediateBlockTypesPlugin, blockStructurePlugin); PluginManager.Instance = pluginManager; PersistenceManager.Instance = new PersistenceManager(persistencePlugin); // Create a project and pull out the useful properties we'll use to // make changes. var project = new Project(); blocks = project.Blocks; commands = project.Commands; plugins = project.Plugins; // Load in the plugins we'll be using in these tests. foreach (IPlugin plugin in pluginManager.Plugins) { plugins.Add(plugin.Key); } // Set up the local words lookup. var localWordsProjectPlugin = (LocalWordsProjectPlugin)plugins["Local Words"]; localWordsProjectPlugin.ReadSettings(); localWordsProjectPlugin.CaseInsensitiveDictionary.Add("teig"); localWordsProjectPlugin.CaseSensitiveDictionary.Add("Moonfire"); localWordsProjectPlugin.WriteSettings(); // Set up the immediate correction plugin. var immediateCorrectionProjectPlugin = (ImmediateCorrectionProjectPlugin)plugins["Immediate Correction"]; immediateCorrectionProjectPlugin.AddSubstitution( "Grey", "Gray", SubstitutionOptions.WholeWord); immediateCorrectionProjectPlugin.AddSubstitution( "GWG", "Great Waryoni Garèo", SubstitutionOptions.None); immediateCorrectionProjectPlugin.AddSubstitution( "GWB", "Great Waryoni Bob", SubstitutionOptions.None); // Set up the immediate block types. var immediateBlockTypesProjectPlugin = (ImmediateBlockTypesProjectPlugin)plugins["Immediate Block Types"]; foreach (BlockType blockType in project.BlockTypes.BlockTypes.Values) { string prefix = string.Format("{0}: ", blockType.Name); immediateBlockTypesProjectPlugin.Settings.Replacements[prefix] = blockType.Name; } // Pull out the projectPlugin for the correction and cast it (since we know // what type it is). ProjectPluginController pluginController = plugins.Controllers[1]; projectPlugin = (FilesystemPersistenceProjectPlugin)pluginController.ProjectPlugin; }
/// <summary> /// Reads the content file, either from the project reader or the Structure /// file depending on the persistence settings. /// </summary> /// <param name="projectReader">The project reader.</param> public void Read(XmlReader projectReader) { // Figure out which reader we'll be using. bool createdReader; XmlReader reader = GetXmlReader( projectReader, Settings.ContentFilename, out createdReader); // Loop through the resulting file until we get to the end of the // XML element we care about. ProjectBlockCollection blocks = Project.Blocks; bool reachedContents = reader.NamespaceURI == XmlConstants.ProjectNamespace && reader.LocalName == "content"; string text = null; BlockType blockType = null; bool firstBlock = true; while (reader.Read()) { // Ignore anything outside of our namespace. if (reader.NamespaceURI != XmlConstants.ProjectNamespace) { continue; } // Check to see if we're done reading. if (reader.NodeType == XmlNodeType.EndElement) { switch (reader.LocalName) { case "content": return; case "block": // Create the block and insert it into the list. var block = new Block(blocks, blockType, text); if (firstBlock) { // Because we have a rule that the collection may // not have less than one block, the first block is // a replacement instead of adding to the list. blocks[0] = block; firstBlock = false; } else { blocks.Add(block); } break; } } // For the rest of this loop, we only deal with begin elements. if (reader.NodeType != XmlNodeType.Element) { continue; } // If we haven't reached the Structure, we just cycle through the XML. if (!reachedContents) { // Flip the flag if we are starting to read the Structure. if (reader.NamespaceURI == XmlConstants.ProjectNamespace && reader.LocalName == "content") { reachedContents = true; } // Continue on since we're done with this if clause. continue; } // We process the remaining elements based on their local name. switch (reader.LocalName) { case "type": string blockTypeName = reader.ReadString(); blockType = Project.BlockTypes[blockTypeName]; break; case "text": text = reader.ReadString(); break; } } // If we created the reader, close it. if (createdReader) { reader.Close(); reader.Dispose(); } }
/// <summary> /// Initializes a new instance of the <see cref="SplitBlockCommand"/> class. /// </summary> /// <param name="position">The position to break the paragraph.</param> public SplitBlockCommand( ProjectBlockCollection blocks, BlockPosition position) : base(position, "\n") { }
/// <summary> /// Reads the content file, either from the project reader or the Structure /// file depending on the persistence settings. /// </summary> /// <param name="projectReader">The project reader.</param> public void Read(XmlReader projectReader) { // Figure out which reader we'll be using. bool createdReader; XmlReader reader = GetXmlReader( projectReader, Settings.ContentDataFilename, out createdReader); // Loop through the resulting file until we get to the end of the // XML element we care about. ProjectBlockCollection blocks = Project.Blocks; bool reachedData = reader.NamespaceURI == XmlConstants.ProjectNamespace && reader.LocalName == "content-data"; int blockIndex = 0; int startTextIndex = 0; int stopTextIndex = 0; ITextControllerProjectPlugin plugin = null; object pluginData = null; bool inProject = false; bool inBlocks = false; while (reader.Read()) { // Ignore anything outside of our namespace. if (reader.NamespaceURI != XmlConstants.ProjectNamespace) { continue; } // Check to see if we're done reading. if (reader.NodeType == XmlNodeType.EndElement) { switch (reader.LocalName) { case "content-data": return; case "text-span": // Construct a text span from the gathered properties. var textSpan = new TextSpan( startTextIndex, stopTextIndex, plugin, pluginData); blocks[blockIndex].TextSpans.Add(textSpan); // Clear out the data to catch any additional errors. plugin = null; pluginData = null; break; case "block-data": inBlocks = false; break; case "project": inProject = false; break; } } // For the rest of this loop, we only deal with begin elements. if (reader.NodeType != XmlNodeType.Element) { continue; } // If we haven't reached the Structure, we just cycle through the XML. if (!reachedData) { // Flip the flag if we are starting to read the Structure. if (reader.NamespaceURI == XmlConstants.ProjectNamespace && reader.LocalName == "content-data") { reachedData = true; } // Continue on since we're done with this if clause. continue; } // We process the remaining elements based on their local name. switch (reader.LocalName) { case "block-data": inBlocks = true; break; case "project": inProject = true; break; case "analyzer": // Grab the analyzer name and find the associated plugin. string key = reader.ReadInnerXml(); if (Project.Plugins.Contains(key)) { var analyzer = Project.Plugins[key] as IBlockAnalyzerProjectPlugin; if (analyzer != null) { blocks[blockIndex].AddAnalysis(analyzer); } } break; case "block-key": // Grab the information to identify the block. We can't use // block key directly so we have an index into the original // block data and a hash of the text. blockIndex = Convert.ToInt32(reader["block-index"]); int textHash = Convert.ToInt32(reader["text-hash"], 16); // Figure out if we are asking for an index that doesn't exist // or if the hash doesn't work. If they don't, then stop // processing entirely. if (blockIndex >= blocks.Count || blocks[blockIndex].Text.GetHashCode() != textHash) { return; } break; case "property": { var path = new HierarchicalPath(reader["path"]); string value = reader.ReadString(); if (inBlocks) { blocks[blockIndex].Properties[path] = value; } if (inProject) { Project.Properties[path] = value; } break; } case "index": startTextIndex = Convert.ToInt32(reader["start"]); stopTextIndex = Convert.ToInt32(reader["stop"]); break; case "plugin": string projectKey = reader.ReadString(); plugin = (ITextControllerProjectPlugin)Project.Plugins[projectKey]; break; } } // If we created the reader, close it. if (createdReader) { reader.Close(); reader.Dispose(); } }
/// <summary> /// Updates the blocks in the project and assign them to block types that fit /// the document structure. This will attempt to keep the current block type /// of a given block if it can fit into the structure. /// </summary> public void Update() { // If we are inside interactive processing, we need to skip updates // since this can be an expensive operation. if (Project.ProcessingState == ProjectProcessingState.Batch) { return; } // We need to get a write lock on the block since we'll be making changes // to all the blocks and their relationships. This will, in effect, also // ensure no block is being modified. using (Project.Blocks.AcquireLock(RequestLock.Write)) { // Go through all the blocks in the list. ProjectBlockCollection blocks = Project.Blocks; for (int blockIndex = 0; blockIndex < Project.Blocks.Count; blockIndex++) { // Grab the block we're currently looking at. Block block = blocks[blockIndex]; BlockType blockType = block.BlockType; // To figure out the block type, we go backwards until we find the // first block's structure that contains this block type. If we // can't find one, we will just use the first block in the list // regardless of type. BlockStructure newBlockStructure = null; Block newParentBlock = null; for (int searchIndex = blockIndex - 1; searchIndex >= 0; searchIndex--) { // Grab this block and structure. Block searchBlock = blocks[searchIndex]; BlockStructure searchStructure = searchBlock.BlockStructure; // If the search structure includes the current block type, // then we'll use that and stop looking through the rest of the list. if (searchStructure.ContainsChildStructure(blockType)) { newBlockStructure = searchStructure.GetChildStructure(blockType); newParentBlock = searchBlock; break; } } // Look to see if we assigned the parent block and structure. If we // haven't, then assign the parent to the first one (obvious not if // we are modifying the first one). if (newParentBlock == null && blockIndex > 0) { newParentBlock = Project.Blocks[0]; } if (newBlockStructure == null) { newBlockStructure = RootBlockStructure; } // Assign the new block structure and parent. block.SetParentBlock(newParentBlock); //block.SetBlockStructure(newBlockStructure); } } }