// // 2002-2005 AlphaSierraPapa // GNU General Public License // // $Revision$ // using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Text; using ICSharpCode.Core; using ICSharpCode.SharpDevelop.Gui; namespace ICSharpCode.SharpDevelop.Project { /// /// An enumerator which enumerates through a list of project items, returning the /// parseable file content of each item. /// /// /// This class is thread-safe in a very limited way: /// It can be created from every thread, but may be only used by the thread that created it. /// It automatically uses WorkbenchSingleton.SafeThreadCall for reading currently open /// files when it is created/accessed from a thread. /// public class ParseableFileContentEnumerator : IEnumerator> { void IEnumerator.Reset() { throw new NotSupportedException(); } KeyValuePair current; object IEnumerator.Current { get { return current; } } public KeyValuePair Current { get { return current; } } public string CurrentFileName { get { return current.Key; } } public string CurrentFileContent { get { return current.Value; } } public void Dispose() { } ProjectItem[] projectItems; bool isOnMainThread; public ParseableFileContentEnumerator(IProject project) : this(project.Items.ToArray()) { } public ParseableFileContentEnumerator(ProjectItem[] projectItems) { isOnMainThread = !WorkbenchSingleton.InvokeRequired; this.projectItems = projectItems; Properties textEditorProperties = ((Properties)PropertyService.Get("ICSharpCode.TextEditor.Document.Document.DefaultDocumentAggregatorProperties", new Properties())); getParseableContentEncoding = Encoding.GetEncoding(textEditorProperties.Get("Encoding", 1252)); pcd = new GetParseableContentDelegate(GetParseableFileContent); if (projectItems.Length > 0) { nextItem = projectItems[0]; } } delegate string GetParseableContentDelegate(IProject project, string fileName); GetParseableContentDelegate pcd; Encoding getParseableContentEncoding; string GetParseableFileContent(IProject project, string fileName) { // Loading the source files is done asynchronously: // While one file is parsed, the next is already loaded from disk. string res = project.GetParseableFileContent(fileName); if (res != null) return res; // load file using (StreamReader r = new StreamReader(fileName, getParseableContentEncoding)) { return r.ReadToEnd(); } } ProjectItem nextItem; IAsyncResult res; int index = 0; public int ItemCount { get { return projectItems.Length; } } public int Index { get { return index; } } public bool MoveNext() { ProjectItem item = nextItem; nextItem = (++index < projectItems.Length) ? projectItems[index] : null; if (item == null) return false; if (item.ItemType != ItemType.Compile) return MoveNext(); string fileContent; try { if (res != null) { fileContent = pcd.EndInvoke(res); } else { fileContent = GetFileContent(item); } } catch (FileNotFoundException ex) { res = null; Console.WriteLine("ParseableFileContentEnumerator: " + ex.Message); return MoveNext(); // skip files that were not found } catch (IOException ex) { res = null; Console.WriteLine("ParseableFileContentEnumerator: " + ex.Message); return MoveNext(); // skip invalid files } if (nextItem != null && nextItem.ItemType == ItemType.Compile && CanReadAsync(nextItem)) res = pcd.BeginInvoke(nextItem.Project, nextItem.FileName, null, null); else res = null; current = new KeyValuePair(item.FileName, fileContent); return true; } string GetFileContent(ProjectItem item) { string fileName = item.FileName; string content; if (isOnMainThread) content = GetFileContentFromOpenFile(fileName); else content = (string)WorkbenchSingleton.SafeThreadCall(this, "GetFileContentFromOpenFile", fileName); if (content != null) return content; return GetParseableFileContent(item.Project, fileName); } string GetFileContentFromOpenFile(string fileName) { IWorkbenchWindow window = FileService.GetOpenFile(fileName); if (window != null) { IViewContent viewContent = window.ViewContent; IEditable editable = viewContent as IEditable; if (editable != null) { return editable.Text; } } return null; } bool CanReadAsync(ProjectItem item) { if (isOnMainThread) return !FileService.IsOpen(item.FileName); else return !(bool)WorkbenchSingleton.SafeThreadCall(typeof(FileService), "IsOpen", item.FileName); } } }