public async static Task <Stetic.CodeGenerationResult> GenerateSteticCode(ProgressMonitor monitor, DotNetProject project, ConfigurationSelector configuration) { if (generating || !GtkDesignInfo.HasDesignedObjects(project)) { return(null); } using (var timer = Counters.SteticFileGeneratedTimer.BeginTiming()) { timer.Trace("Checking references"); GtkDesignInfo info = GtkDesignInfo.FromProject(project); DateTime last_gen_time = File.Exists(info.SteticGeneratedFile) ? File.GetLastWriteTime(info.SteticGeneratedFile) : DateTime.MinValue; bool ref_changed = false; // Disabled check for changes in referenced assemblies, since it cause too much // regeneration of code. If a component has changed in a referenced project, this // project may not build, but this can be solved by editing some file in the // designer and saving. /* foreach (ProjectReference pref in project.References) { * if (!pref.IsValid) * continue; * foreach (string filename in pref.GetReferencedFileNames (configuration)) { * if (File.GetLastWriteTime (filename) > last_gen_time) { * ref_changed = true; * break; * } * } * if (ref_changed) * break; * }*/ // Check if generated code is already up to date. if (!ref_changed && last_gen_time >= File.GetLastWriteTime(info.SteticFile)) { return(null); } if (info.GuiBuilderProject.HasError) { var error = GettextCatalog.GetString("GUI code generation failed for project '{0}'. The file '{1}' could not be loaded.", project.Name, info.SteticFile); monitor.ReportError(error, null); throw new UserException(error); } if (info.GuiBuilderProject.IsEmpty) { return(null); } monitor.Log.WriteLine(GettextCatalog.GetString("Generating GUI code for project '{0}'...", project.Name)); timer.Trace("Copy support files"); // Make sure the referenced assemblies are up to date. It is necessary to do // it now since they may contain widget libraries. project.CopySupportFiles(monitor, configuration); timer.Trace("Update libraries"); info.GuiBuilderProject.UpdateLibraries(); ArrayList projects = new ArrayList(); projects.Add(info.GuiBuilderProject.File); generating = true; Stetic.CodeGenerationResult generationResult = null; Exception generatedException = null; bool canGenerateInProcess = IsolationMode != Stetic.IsolationMode.None || info.GuiBuilderProject.SteticProject.CanGenerateCode; if (!canGenerateInProcess) { timer.Trace("Generating out of process"); await Task.Run(delegate { try { // Generate the code in another process if stetic is not isolated CodeGeneratorProcess cob = (CodeGeneratorProcess)Runtime.ProcessService.CreateExternalProcessObject(typeof(CodeGeneratorProcess), false); using (cob) { generationResult = cob.GenerateCode(projects, info.GenerateGettext, info.GettextClass, info.ImageResourceLoaderClass, project.UsePartialTypes); } } catch (Exception ex) { generatedException = ex; } finally { generating = false; } }); } else { timer.Trace("Generating in-process"); // No need to create another process, since stetic has its own backend process // or the widget libraries have no custom wrappers try { Stetic.GenerationOptions options = new Stetic.GenerationOptions(); options.UseGettext = info.GenerateGettext; options.GettextClass = info.GettextClass; options.ImageResourceLoaderClass = info.ImageResourceLoaderClass; options.UsePartialClasses = project.UsePartialTypes; options.GenerateSingleFile = false; options.GenerateModifiedOnly = true; generationResult = SteticApp.GenerateProjectCode(options, info.GuiBuilderProject.SteticProject); info.GuiBuilderProject.SteticProject.ResetModifiedWidgetFlags(); } catch (Exception ex) { generatedException = ex; } generating = false; } timer.Trace("Writing code units"); if (generatedException != null) { LoggingService.LogError("GUI code generation failed", generatedException); throw new UserException("GUI code generation failed: " + generatedException.Message); } if (generationResult == null) { return(null); } CodeDomProvider provider = project.LanguageBinding.GetCodeDomProvider(); if (provider == null) { throw new UserException("Code generation not supported for language: " + project.LanguageName); } string basePath = Path.GetDirectoryName(info.SteticGeneratedFile); string ext = Path.GetExtension(info.SteticGeneratedFile); var pol = project.Policies.Get <TextStylePolicy> (); var codeGeneratorOptions = new CodeGeneratorOptions() { IndentString = pol.TabsToSpaces? new string (' ', pol.TabWidth) : "\t", BlankLinesBetweenMembers = true }; foreach (Stetic.SteticCompilationUnit unit in generationResult.Units) { string fname; if (unit.Name.Length == 0) { fname = info.SteticGeneratedFile; } else { fname = Path.Combine(basePath, unit.Name) + ext; } StringWriter sw = new StringWriter(); try { foreach (CodeNamespace ns in unit.Namespaces) { ns.Comments.Add(new CodeCommentStatement("This file has been generated by the GUI designer. Do not modify.")); } timer.Trace("Generating code for " + unit.Name); provider.GenerateCodeFromCompileUnit(unit, sw, codeGeneratorOptions); string content = sw.ToString(); timer.Trace("Formatting code"); content = FormatGeneratedFile(fname, content, project, provider); timer.Trace("Writing code"); File.WriteAllText(fname, content); } finally { timer.Trace("Notifying changes"); FileService.NotifyFileChanged(fname); } } timer.Trace("Updating GTK folder"); // Make sure the generated files are added to the project if (info.UpdateGtkFolder()) { Gtk.Application.Invoke(delegate { IdeApp.ProjectOperations.SaveAsync(project); }); } return(generationResult); } }
public static Stetic.CodeGenerationResult GenerateSteticCode(IProgressMonitor monitor, DotNetProject project, ConfigurationSelector configuration) { if (generating || !GtkDesignInfo.HasDesignedObjects(project)) { return(null); } GtkDesignInfo info = GtkDesignInfo.FromProject(project); info.CheckGtkFolder(); DateTime last_gen_time = File.Exists(info.SteticGeneratedFile) ? File.GetLastWriteTime(info.SteticGeneratedFile) : DateTime.MinValue; bool ref_changed = false; foreach (ProjectReference pref in project.References) { if (!pref.IsValid) { continue; } foreach (string filename in pref.GetReferencedFileNames(configuration)) { if (File.GetLastWriteTime(filename) > last_gen_time) { ref_changed = true; break; } } if (ref_changed) { break; } } // Check if generated code is already up to date. // if (!ref_changed && last_gen_time >= File.GetLastWriteTime (info.SteticFile)) // return null; if (info.GuiBuilderProject.HasError) { monitor.ReportError(GettextCatalog.GetString("GUI code generation failed for project '{0}'. The file '{1}' could not be loaded.", project.Name, info.SteticFile), null); monitor.AsyncOperation.Cancel(); return(null); } if (info.GuiBuilderProject.IsEmpty) { return(null); } monitor.Log.WriteLine(GettextCatalog.GetString("Generating GUI code for project '{0}'...", project.Name)); // Make sure the referenced assemblies are up to date. It is necessary to do // it now since they may contain widget libraries. project.CopySupportFiles(monitor, configuration); info.GuiBuilderProject.UpdateLibraries(); ArrayList projectFolders = new ArrayList(); projectFolders.Add(info.SteticFolder.FullPath); generating = true; Stetic.CodeGenerationResult generationResult = null; Exception generatedException = null; bool canGenerateInProcess = IsolationMode != Stetic.IsolationMode.None || info.GuiBuilderProject.SteticProject.CanGenerateCode; if (!canGenerateInProcess) { // Run the generation in another thread to avoid freezing the GUI System.Threading.ThreadPool.QueueUserWorkItem(delegate { try { // Generate the code in another process if stetic is not isolated CodeGeneratorProcess cob = (CodeGeneratorProcess)Runtime.ProcessService.CreateExternalProcessObject(typeof(CodeGeneratorProcess), false); using (cob) { generationResult = cob.GenerateCode(projectFolders, info.GenerateGettext, info.GettextClass, project.UsePartialTypes, info); } } catch (Exception ex) { generatedException = ex; } finally { generating = false; } }); while (generating) { DispatchService.RunPendingEvents(); System.Threading.Thread.Sleep(100); } } else { // No need to create another process, since stetic has its own backend process // or the widget libraries have no custom wrappers try { Stetic.GenerationOptions options = new Stetic.GenerationOptions(); options.UseGettext = info.GenerateGettext; options.GettextClass = info.GettextClass; generationResult = SteticApp.GenerateProjectCode(options, info.GuiBuilderProject.SteticProject); } catch (Exception ex) { generatedException = ex; } generating = false; } if (generatedException != null) { string msg = string.Empty; if (generatedException.InnerException != null) { msg = string.Format("{0}\n{1}\nInner Exception {2}\n{3}", generatedException.Message, generatedException.StackTrace, generatedException.InnerException.Message, generatedException.InnerException.StackTrace); } else { msg = string.Format("{0}\n{1}", generatedException.Message, generatedException.StackTrace); } // LoggingService.LogError ("GUI code generation failed", generatedException); LoggingService.LogError("GUI code generation failed: " + msg); throw new UserException("GUI code generation failed: " + msg); } if (generationResult == null) { return(null); } CodeDomProvider provider = project.LanguageBinding.GetCodeDomProvider(); if (provider == null) { throw new UserException("Code generation not supported for language: " + project.LanguageName); } foreach (Stetic.SteticCompilationUnit unit in generationResult.Units) { string fname; if (unit.Name.Length == 0) { fname = info.SteticGeneratedFile; } else { fname = GetBuildCodeFileName(project, unit.Name, (unit.Namespace != null) ? unit.Namespace.Name : string.Empty); } StringWriter sw = new StringWriter(); try { foreach (CodeNamespace ns in unit.Namespaces) { ns.Comments.Add(new CodeCommentStatement("This file has been generated by the GUI designer. Do not modify.")); } provider.GenerateCodeFromCompileUnit(unit, sw, new CodeGeneratorOptions()); string content = sw.ToString(); content = FormatGeneratedFile(fname, content, provider); File.WriteAllText(fname, content); } finally { FileService.NotifyFileChanged(fname); } } // Make sure the generated files are added to the project if (info.UpdateGtkFolder()) { Gtk.Application.Invoke(delegate { IdeApp.ProjectOperations.Save(project); }); } return(generationResult); }